1/* 2 * (C) 2012 by Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 3 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> 4 * 5 * Based on: RPC extension for conntrack. 6 * 7 * This port has been sponsored by Vyatta Inc. <http://www.vyatta.com> 8 * 9 * Original copyright notice: 10 * 11 * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br> 12 * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au> 13 * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au> 14 * (C) 2004,2005 by David Stes <stes@pandora.be> 15 * 16 * This program is free software; you can redistribute it and/or modify 17 * it under the terms of the GNU General Public License version 2 as 18 * published by the Free Software Foundation. 19 */ 20 21#include "conntrackd.h" 22#include "network.h" /* for before and after */ 23#include "helper.h" 24#include "myct.h" 25#include "log.h" 26 27#include <errno.h> 28 29#include <rpc/rpc_msg.h> 30#include <rpc/pmap_prot.h> 31#include <netinet/tcp.h> 32#include <netinet/udp.h> 33 34#include <libmnl/libmnl.h> 35#include <libnetfilter_conntrack/libnetfilter_conntrack.h> 36#include <libnetfilter_queue/libnetfilter_queue.h> 37#include <libnetfilter_queue/libnetfilter_queue_tcp.h> 38#include <libnetfilter_queue/pktbuff.h> 39#include <linux/netfilter.h> 40 41/* RFC 1050: RPC: Remote Procedure Call Protocol Specification Version 2 */ 42/* RFC 1014: XDR: External Data Representation Standard */ 43#define SUPPORTED_RPC_VERSION 2 44 45struct rpc_info { 46 /* XID */ 47 uint32_t xid; 48 /* program */ 49 uint32_t pm_prog; 50 /* program version */ 51 uint32_t pm_vers; 52 /* transport protocol: TCP|UDP */ 53 uint32_t pm_prot; 54}; 55 56/* So, this packet has hit the connection tracking matching code. 57 Mangle it, and change the expectation to match the new version. */ 58static unsigned int 59nf_nat_rpc(struct pkt_buff *pkt, int dir, struct nf_expect *exp, 60 uint8_t proto, uint32_t *port_ptr) 61{ 62 const struct nf_conntrack *expected; 63 struct nf_conntrack *nat_tuple; 64 uint16_t initial_port, port; 65 66 expected = nfexp_get_attr(exp, ATTR_EXP_EXPECTED); 67 68 nat_tuple = nfct_new(); 69 if (nat_tuple == NULL) 70 return NF_ACCEPT; 71 72 initial_port = nfct_get_attr_u16(expected, ATTR_PORT_DST); 73 74 nfexp_set_attr_u32(exp, ATTR_EXP_NAT_DIR, !dir); 75 76 /* libnetfilter_conntrack needs this */ 77 nfct_set_attr_u8(nat_tuple, ATTR_L3PROTO, AF_INET); 78 nfct_set_attr_u32(nat_tuple, ATTR_IPV4_SRC, 0); 79 nfct_set_attr_u32(nat_tuple, ATTR_IPV4_DST, 0); 80 nfct_set_attr_u8(nat_tuple, ATTR_L4PROTO, proto); 81 nfct_set_attr_u16(nat_tuple, ATTR_PORT_DST, 0); 82 83 /* When you see the packet, we need to NAT it the same as the 84 * this one. */ 85 nfexp_set_attr(exp, ATTR_EXP_FN, "nat-follow-master"); 86 87 /* Try to get same port: if not, try to change it. */ 88 for (port = ntohs(initial_port); port != 0; port++) { 89 int ret; 90 91 nfct_set_attr_u16(nat_tuple, ATTR_PORT_SRC, htons(port)); 92 nfexp_set_attr(exp, ATTR_EXP_NAT_TUPLE, nat_tuple); 93 94 ret = cthelper_add_expect(exp); 95 if (ret == 0) 96 break; 97 else if (ret != -EBUSY) { 98 port = 0; 99 break; 100 } 101 } 102 nfct_destroy(nat_tuple); 103 104 if (port == 0) 105 return NF_DROP; 106 107 *port_ptr = htonl(port); 108 109 return NF_ACCEPT; 110} 111 112#define OFFSET(o, n) ((o) += n) 113#define ROUNDUP(n) ((((n) + 3)/4)*4) 114 115static int 116rpc_call(const uint32_t *data, uint32_t offset, uint32_t datalen, 117 struct rpc_info *rpc_info) 118{ 119 uint32_t p, r; 120 121 /* RPC CALL message body */ 122 123 /* call_body { 124 * rpcvers 125 * prog 126 * vers 127 * proc 128 * opaque_auth cred 129 * opaque_auth verf 130 * pmap 131 * } 132 * 133 * opaque_auth { 134 * flavour 135 * opaque[len] <= MAX_AUTH_BYTES 136 * } 137 */ 138 if (datalen < OFFSET(offset, 4*4 + 2*2*4)) { 139 pr_debug("RPC CALL: too short packet: %u < %u\n", 140 datalen, offset); 141 return -1; 142 } 143 /* Check rpcversion */ 144 p = IXDR_GET_INT32(data); 145 if (p != SUPPORTED_RPC_VERSION) { 146 pr_debug("RPC CALL: wrong rpcvers %u != %u\n", 147 p, SUPPORTED_RPC_VERSION); 148 return -1; 149 } 150 /* Skip non-portmap requests */ 151 p = IXDR_GET_INT32(data); 152 if (p != PMAPPROG) { 153 pr_debug("RPC CALL: not portmap %u != %lu\n", 154 p, PMAPPROG); 155 return -1; 156 } 157 /* Check portmap version */ 158 p = IXDR_GET_INT32(data); 159 if (p != PMAPVERS) { 160 pr_debug("RPC CALL: wrong portmap version %u != %lu\n", 161 p, PMAPVERS); 162 return -1; 163 } 164 /* Skip non PMAPPROC_GETPORT requests */ 165 p = IXDR_GET_INT32(data); 166 if (p != PMAPPROC_GETPORT) { 167 pr_debug("RPC CALL: not PMAPPROC_GETPORT %u != %lu\n", 168 p, PMAPPROC_GETPORT); 169 return -1; 170 } 171 /* Check and skip credentials */ 172 r = IXDR_GET_INT32(data); 173 p = IXDR_GET_INT32(data); 174 pr_debug("RPC CALL: cred: %u %u (%u, %u)\n", 175 r, p, datalen, offset); 176 if (p > MAX_AUTH_BYTES) { 177 pr_debug("RPC CALL: invalid sized cred %u > %u\n", 178 p, MAX_AUTH_BYTES); 179 return -1; 180 } 181 r = ROUNDUP(p); 182 if (datalen < OFFSET(offset, r)) { 183 pr_debug("RPC CALL: too short to carry cred: %u < %u, %u\n", 184 datalen, offset, r); 185 return -1; 186 } 187 data += r/4; 188 /* Check and skip verifier */ 189 r = IXDR_GET_INT32(data); 190 p = IXDR_GET_INT32(data); 191 pr_debug("RPC CALL: verf: %u %u (%u, %u)\n", 192 r, p, datalen, offset); 193 if (p > MAX_AUTH_BYTES) { 194 pr_debug("RPC CALL: invalid sized verf %u > %u\n", 195 p, MAX_AUTH_BYTES); 196 return -1; 197 } 198 r = ROUNDUP(p); 199 if (datalen < OFFSET(offset, r)) { 200 pr_debug("RPC CALL: too short to carry verf: %u < %u, %u\n", 201 datalen, offset, r); 202 return -1; 203 } 204 data += r/4; 205 /* pmap { 206 * prog 207 * vers 208 * prot 209 * port 210 * } 211 */ 212 /* Check CALL size */ 213 if (datalen != offset + 4*4) { 214 pr_debug("RPC CALL: invalid size to carry pmap: %u != %u\n", 215 datalen, offset + 4*4); 216 return -1; 217 } 218 rpc_info->pm_prog = IXDR_GET_INT32(data); 219 rpc_info->pm_vers = IXDR_GET_INT32(data); 220 rpc_info->pm_prot = IXDR_GET_INT32(data); 221 /* Check supported protocols */ 222 if (!(rpc_info->pm_prot == IPPROTO_TCP 223 || rpc_info->pm_prot == IPPROTO_UDP)) { 224 pr_debug("RPC CALL: unsupported protocol %u", 225 rpc_info->pm_prot); 226 return -1; 227 } 228 p = IXDR_GET_INT32(data); 229 /* Check port: must be zero */ 230 if (p != 0) { 231 pr_debug("RPC CALL: port is nonzero %u\n", 232 ntohl(p)); 233 return -1; 234 } 235 pr_debug("RPC CALL: processed: xid %u, prog %u, vers %u, prot %u\n", 236 rpc_info->xid, rpc_info->pm_prog, 237 rpc_info->pm_vers, rpc_info->pm_prot); 238 239 return 0; 240} 241 242static int 243rpc_reply(uint32_t *data, uint32_t offset, uint32_t datalen, 244 struct rpc_info *rpc_info, uint32_t **port_ptr) 245{ 246 uint16_t port; 247 uint32_t p, r; 248 249 /* RPC REPLY message body */ 250 251 /* reply_body { 252 * reply_stat 253 * xdr_union { 254 * accepted_reply 255 * rejected_reply 256 * } 257 * } 258 * accepted_reply { 259 * opaque_auth verf 260 * accept_stat 261 * xdr_union { 262 * port 263 * struct mismatch_info 264 * } 265 * } 266 */ 267 268 /* Check size: reply status */ 269 if (datalen < OFFSET(offset, 4)) { 270 pr_debug("RPC REPL: too short, missing rp_stat: %u < %u\n", 271 datalen, offset); 272 return -1; 273 } 274 p = IXDR_GET_INT32(data); 275 /* Check accepted request */ 276 if (p != MSG_ACCEPTED) { 277 pr_debug("RPC REPL: not accepted %u != %u\n", 278 p, MSG_ACCEPTED); 279 return -1; 280 } 281 /* Check and skip verifier */ 282 if (datalen < OFFSET(offset, 2*4)) { 283 pr_debug("RPC REPL: too short, missing verf: %u < %u\n", 284 datalen, offset); 285 return -1; 286 } 287 r = IXDR_GET_INT32(data); 288 p = IXDR_GET_INT32(data); 289 pr_debug("RPC REPL: verf: %u %u (%u, %u)\n", 290 r, p, datalen, offset); 291 if (p > MAX_AUTH_BYTES) { 292 pr_debug("RPC REPL: invalid sized verf %u > %u\n", 293 p, MAX_AUTH_BYTES); 294 return -1; 295 } 296 r = ROUNDUP(p); 297 /* verifier + ac_stat + port */ 298 if (datalen != OFFSET(offset, r) + 2*4) { 299 pr_debug("RPC REPL: invalid size to carry verf and " 300 "success: %u != %u\n", 301 datalen, offset + 2*4); 302 return -1; 303 } 304 data += r/4; 305 /* Check success */ 306 p = IXDR_GET_INT32(data); 307 if (p != SUCCESS) { 308 pr_debug("RPC REPL: not success %u != %u\n", 309 p, SUCCESS); 310 return -1; 311 } 312 /* Get port */ 313 *port_ptr = data; 314 port = IXDR_GET_INT32(data); /* -Wunused-but-set-parameter */ 315 if (port == 0) { 316 pr_debug("RPC REPL: port is zero\n"); 317 return -1; 318 } 319 pr_debug("RPC REPL: processed: xid %u, prog %u, vers %u, " 320 "prot %u, port %u\n", 321 rpc_info->xid, rpc_info->pm_prog, rpc_info->pm_vers, 322 rpc_info->pm_prot, port); 323 return 0; 324} 325 326static int 327rpc_helper_cb(struct pkt_buff *pkt, uint32_t protoff, 328 struct myct *myct, uint32_t ctinfo) 329{ 330 int dir = CTINFO2DIR(ctinfo); 331 unsigned int offset = protoff, datalen; 332 uint32_t *data, *port_ptr = NULL, xid; 333 uint16_t port; 334 uint8_t proto = nfct_get_attr_u8(myct->ct, ATTR_L4PROTO); 335 enum msg_type rm_dir; 336 struct rpc_info *rpc_info = myct->priv_data; 337 union nfct_attr_grp_addr addr, daddr; 338 struct nf_expect *exp = NULL; 339 int ret = NF_ACCEPT; 340 341 /* Until there's been traffic both ways, don't look into TCP packets. */ 342 if (proto == IPPROTO_TCP 343 && ctinfo != IP_CT_ESTABLISHED 344 && ctinfo != IP_CT_ESTABLISHED_REPLY) { 345 pr_debug("TCP RPC: Conntrackinfo = %u\n", ctinfo); 346 return ret; 347 } 348 if (proto == IPPROTO_TCP) { 349 struct tcphdr *th = 350 (struct tcphdr *) (pktb_network_header(pkt) + protoff); 351 offset += th->doff * 4; 352 } else { 353 offset += sizeof(struct udphdr); 354 } 355 /* Skip broken headers */ 356 if (offset % 4) { 357 pr_debug("RPC: broken header: offset %u%%4 != 0\n", offset); 358 return ret; 359 } 360 361 /* Take into Record Fragment header */ 362 if (proto == IPPROTO_TCP) 363 offset += 4; 364 365 datalen = pktb_len(pkt); 366 data = (uint32_t *)(pktb_network_header(pkt) + offset); 367 368 /* rpc_msg { 369 * xid 370 * direction 371 * xdr_union { 372 * call_body 373 * reply_body 374 * } 375 * } 376 */ 377 378 /* Check minimal msg size: xid + direction */ 379 if (datalen < OFFSET(offset, 2*4)) { 380 pr_debug("RPC: too short packet: %u < %u\n", 381 datalen, offset); 382 return ret; 383 } 384 xid = IXDR_GET_INT32(data); 385 rm_dir = IXDR_GET_INT32(data); 386 387 /* Check direction */ 388 if (!((rm_dir == CALL && dir == MYCT_DIR_ORIG) 389 || (rm_dir == REPLY && dir == MYCT_DIR_REPL))) { 390 pr_debug("RPC: rm_dir != dir %u != %u\n", rm_dir, dir); 391 goto out; 392 } 393 394 if (rm_dir == CALL) { 395 if (rpc_call(data, offset, datalen, rpc_info) < 0) 396 goto out; 397 398 rpc_info->xid = xid; 399 400 return ret; 401 } else { 402 /* Check XID */ 403 if (xid != rpc_info->xid) { 404 pr_debug("RPC REPL: XID does not match: %u != %u\n", 405 xid, rpc_info->xid); 406 goto out; 407 } 408 if (rpc_reply(data, offset, datalen, rpc_info, &port_ptr) < 0) 409 goto out; 410 411 port = IXDR_GET_INT32(port_ptr); 412 port = htons(port); 413 414 /* We refer to the reverse direction ("!dir") tuples here, 415 * because we're expecting something in the other direction. 416 * Doesn't matter unless NAT is happening. */ 417 cthelper_get_addr_dst(myct->ct, !dir, &daddr); 418 cthelper_get_addr_src(myct->ct, !dir, &addr); 419 420 exp = nfexp_new(); 421 if (exp == NULL) 422 goto out; 423 424 if (cthelper_expect_init(exp, myct->ct, 0, &addr, &daddr, 425 rpc_info->pm_prot, 426 NULL, &port, NF_CT_EXPECT_PERMANENT)) { 427 pr_debug("RPC: failed to init expectation\n"); 428 goto out_exp; 429 } 430 431 /* Now, NAT might want to mangle the packet, and register the 432 * (possibly changed) expectation itself. */ 433 if (nfct_get_attr_u32(myct->ct, ATTR_STATUS) & IPS_NAT_MASK) { 434 ret = nf_nat_rpc(pkt, dir, exp, rpc_info->pm_prot, 435 port_ptr); 436 goto out_exp; 437 } 438 439 /* Can't expect this? Best to drop packet now. */ 440 if (cthelper_add_expect(exp) < 0) { 441 pr_debug("RPC: cannot add expectation: %s\n", 442 strerror(errno)); 443 ret = NF_DROP; 444 } 445 } 446 447out_exp: 448 nfexp_destroy(exp); 449out: 450 rpc_info->xid = 0; 451 return ret; 452} 453 454static struct ctd_helper rpc_helper_tcp = { 455 .name = "rpc", 456 .l4proto = IPPROTO_TCP, 457 .cb = rpc_helper_cb, 458 .priv_data_len = sizeof(struct rpc_info), 459 .policy = { 460 { 461 .name = "rpc", 462 .expect_max = 1, 463 .expect_timeout = 300, 464 }, 465 }, 466}; 467 468static struct ctd_helper rpc_helper_udp = { 469 .name = "rpc", 470 .l4proto = IPPROTO_UDP, 471 .cb = rpc_helper_cb, 472 .priv_data_len = sizeof(struct rpc_info), 473 .policy = { 474 { 475 .name = "rpc", 476 .expect_max = 1, 477 .expect_timeout = 300, 478 }, 479 }, 480}; 481 482void __attribute__ ((constructor)) rpc_init(void); 483 484void rpc_init(void) 485{ 486 helper_register(&rpc_helper_tcp); 487 helper_register(&rpc_helper_udp); 488} 489