Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_conntrack_sip: add TCP support

Add TCP support, which is mandated by RFC3261 for all SIP elements.

SIP over TCP is similar to UDP, except that messages are delimited
by Content-Length: headers and multiple messages may appear in one
packet.

Signed-off-by: Patrick McHardy <kaber@trash.net>

+182 -34
+2 -1
include/linux/netfilter/nf_conntrack_sip.h
··· 84 84 SIP_HDR_FROM, 85 85 SIP_HDR_TO, 86 86 SIP_HDR_CONTACT, 87 - SIP_HDR_VIA, 87 + SIP_HDR_VIA_UDP, 88 + SIP_HDR_VIA_TCP, 88 89 SIP_HDR_EXPIRES, 89 90 SIP_HDR_CONTENT_LENGTH, 90 91 };
+1 -1
net/ipv4/netfilter/nf_nat_sip.c
··· 122 122 123 123 /* Translate topmost Via header and parameters */ 124 124 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, 125 - SIP_HDR_VIA, NULL, &matchoff, &matchlen, 125 + SIP_HDR_VIA_UDP, NULL, &matchoff, &matchlen, 126 126 &addr, &port) > 0) { 127 127 unsigned int matchend, poff, plen, buflen, n; 128 128 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+179 -32
net/netfilter/nf_conntrack_sip.c
··· 16 16 #include <linux/inet.h> 17 17 #include <linux/in.h> 18 18 #include <linux/udp.h> 19 + #include <linux/tcp.h> 19 20 #include <linux/netfilter.h> 20 21 21 22 #include <net/netfilter/nf_conntrack.h> ··· 288 287 [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), 289 288 [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), 290 289 [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), 291 - [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), 290 + [SIP_HDR_VIA_UDP] = SIP_HDR("Via", "v", "UDP ", epaddr_len), 291 + [SIP_HDR_VIA_TCP] = SIP_HDR("Via", "v", "TCP ", epaddr_len), 292 292 [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len), 293 293 [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), 294 294 }; ··· 521 519 } 522 520 EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); 523 521 522 + static int ct_sip_parse_param(const struct nf_conn *ct, const char *dptr, 523 + unsigned int dataoff, unsigned int datalen, 524 + const char *name, 525 + unsigned int *matchoff, unsigned int *matchlen) 526 + { 527 + const char *limit = dptr + datalen; 528 + const char *start; 529 + const char *end; 530 + 531 + limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); 532 + if (!limit) 533 + limit = dptr + datalen; 534 + 535 + start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); 536 + if (!start) 537 + return 0; 538 + start += strlen(name); 539 + 540 + end = ct_sip_header_search(start, limit, ";", strlen(";")); 541 + if (!end) 542 + end = limit; 543 + 544 + *matchoff = start - dptr; 545 + *matchlen = end - start; 546 + return 1; 547 + } 548 + 524 549 /* Parse address from header parameter and return address, offset and length */ 525 550 int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, 526 551 unsigned int dataoff, unsigned int datalen, ··· 605 576 return 1; 606 577 } 607 578 EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param); 579 + 580 + static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, 581 + unsigned int dataoff, unsigned int datalen, 582 + u8 *proto) 583 + { 584 + unsigned int matchoff, matchlen; 585 + 586 + if (ct_sip_parse_param(ct, dptr, dataoff, datalen, "transport=", 587 + &matchoff, &matchlen)) { 588 + if (!strnicmp(dptr + matchoff, "TCP", strlen("TCP"))) 589 + *proto = IPPROTO_TCP; 590 + else if (!strnicmp(dptr + matchoff, "UDP", strlen("UDP"))) 591 + *proto = IPPROTO_UDP; 592 + else 593 + return 0; 594 + 595 + if (*proto != nf_ct_protonum(ct)) 596 + return 0; 597 + } else 598 + *proto = nf_ct_protonum(ct); 599 + 600 + return 1; 601 + } 608 602 609 603 /* SDP header parsing: a SDP session description contains an ordered set of 610 604 * headers, starting with a section containing general session parameters, ··· 737 685 738 686 static int refresh_signalling_expectation(struct nf_conn *ct, 739 687 union nf_inet_addr *addr, 740 - __be16 port, 688 + u8 proto, __be16 port, 741 689 unsigned int expires) 742 690 { 743 691 struct nf_conn_help *help = nfct_help(ct); ··· 749 697 hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { 750 698 if (exp->class != SIP_EXPECT_SIGNALLING || 751 699 !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || 700 + exp->tuple.dst.protonum != proto || 752 701 exp->tuple.dst.u.udp.port != port) 753 702 continue; 754 703 if (!del_timer(&exp->timeout)) ··· 1101 1048 struct nf_conntrack_expect *exp; 1102 1049 union nf_inet_addr *saddr, daddr; 1103 1050 __be16 port; 1051 + u8 proto; 1104 1052 unsigned int expires = 0; 1105 1053 int ret; 1106 1054 typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; ··· 1134 1080 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr)) 1135 1081 return NF_ACCEPT; 1136 1082 1083 + if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, *datalen, 1084 + &proto) == 0) 1085 + return NF_ACCEPT; 1086 + 1137 1087 if (ct_sip_parse_numerical_param(ct, *dptr, 1138 1088 matchoff + matchlen, *datalen, 1139 1089 "expires=", NULL, NULL, &expires) < 0) ··· 1157 1099 saddr = &ct->tuplehash[!dir].tuple.src.u3; 1158 1100 1159 1101 nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), 1160 - saddr, &daddr, IPPROTO_UDP, NULL, &port); 1102 + saddr, &daddr, proto, NULL, &port); 1161 1103 exp->timeout.expires = sip_timeout * HZ; 1162 1104 exp->helper = nfct_help(ct)->helper; 1163 1105 exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; ··· 1190 1132 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 1191 1133 union nf_inet_addr addr; 1192 1134 __be16 port; 1135 + u8 proto; 1193 1136 unsigned int matchoff, matchlen, coff = 0; 1194 1137 unsigned int expires = 0; 1195 1138 int in_contact = 0, ret; ··· 1231 1172 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr)) 1232 1173 continue; 1233 1174 1175 + if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, 1176 + *datalen, &proto) == 0) 1177 + continue; 1178 + 1234 1179 ret = ct_sip_parse_numerical_param(ct, *dptr, 1235 1180 matchoff + matchlen, 1236 1181 *datalen, "expires=", ··· 1243 1180 return NF_DROP; 1244 1181 if (c_expires == 0) 1245 1182 break; 1246 - if (refresh_signalling_expectation(ct, &addr, port, c_expires)) 1183 + if (refresh_signalling_expectation(ct, &addr, proto, port, 1184 + c_expires)) 1247 1185 return NF_ACCEPT; 1248 1186 } 1249 1187 ··· 1329 1265 return NF_ACCEPT; 1330 1266 } 1331 1267 1332 - static int sip_help(struct sk_buff *skb, 1333 - unsigned int protoff, 1334 - struct nf_conn *ct, 1335 - enum ip_conntrack_info ctinfo) 1268 + static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct, 1269 + unsigned int dataoff, const char **dptr, 1270 + unsigned int *datalen) 1271 + { 1272 + typeof(nf_nat_sip_hook) nf_nat_sip; 1273 + int ret; 1274 + 1275 + if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) 1276 + ret = process_sip_request(skb, dataoff, dptr, datalen); 1277 + else 1278 + ret = process_sip_response(skb, dataoff, dptr, datalen); 1279 + 1280 + if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { 1281 + nf_nat_sip = rcu_dereference(nf_nat_sip_hook); 1282 + if (nf_nat_sip && !nf_nat_sip(skb, dataoff, dptr, datalen)) 1283 + ret = NF_DROP; 1284 + } 1285 + 1286 + return ret; 1287 + } 1288 + 1289 + static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, 1290 + struct nf_conn *ct, enum ip_conntrack_info ctinfo) 1291 + { 1292 + struct tcphdr *th, _tcph; 1293 + unsigned int dataoff, datalen; 1294 + unsigned int matchoff, matchlen, clen; 1295 + unsigned int msglen, origlen; 1296 + const char *dptr, *end; 1297 + s16 diff, tdiff = 0; 1298 + int ret; 1299 + 1300 + if (ctinfo != IP_CT_ESTABLISHED && 1301 + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) 1302 + return NF_ACCEPT; 1303 + 1304 + /* No Data ? */ 1305 + th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); 1306 + if (th == NULL) 1307 + return NF_ACCEPT; 1308 + dataoff = protoff + th->doff * 4; 1309 + if (dataoff >= skb->len) 1310 + return NF_ACCEPT; 1311 + 1312 + nf_ct_refresh(ct, skb, sip_timeout * HZ); 1313 + 1314 + if (skb_is_nonlinear(skb)) { 1315 + pr_debug("Copy of skbuff not supported yet.\n"); 1316 + return NF_ACCEPT; 1317 + } 1318 + 1319 + dptr = skb->data + dataoff; 1320 + datalen = skb->len - dataoff; 1321 + if (datalen < strlen("SIP/2.0 200")) 1322 + return NF_ACCEPT; 1323 + 1324 + while (1) { 1325 + if (ct_sip_get_header(ct, dptr, 0, datalen, 1326 + SIP_HDR_CONTENT_LENGTH, 1327 + &matchoff, &matchlen) <= 0) 1328 + break; 1329 + 1330 + clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); 1331 + if (dptr + matchoff == end) 1332 + break; 1333 + 1334 + if (end + strlen("\r\n\r\n") > dptr + datalen) 1335 + break; 1336 + if (end[0] != '\r' || end[1] != '\n' || 1337 + end[2] != '\r' || end[3] != '\n') 1338 + break; 1339 + end += strlen("\r\n\r\n") + clen; 1340 + 1341 + msglen = origlen = end - dptr; 1342 + 1343 + ret = process_sip_msg(skb, ct, dataoff, &dptr, &msglen); 1344 + if (ret != NF_ACCEPT) 1345 + break; 1346 + diff = msglen - origlen; 1347 + tdiff += diff; 1348 + 1349 + dataoff += msglen; 1350 + dptr += msglen; 1351 + datalen = datalen + diff - msglen; 1352 + } 1353 + 1354 + return ret; 1355 + } 1356 + 1357 + static int sip_help_udp(struct sk_buff *skb, unsigned int protoff, 1358 + struct nf_conn *ct, enum ip_conntrack_info ctinfo) 1336 1359 { 1337 1360 unsigned int dataoff, datalen; 1338 1361 const char *dptr; 1339 - int ret; 1340 - typeof(nf_nat_sip_hook) nf_nat_sip; 1341 1362 1342 1363 /* No Data ? */ 1343 1364 dataoff = protoff + sizeof(struct udphdr); ··· 1431 1282 1432 1283 nf_ct_refresh(ct, skb, sip_timeout * HZ); 1433 1284 1434 - if (!skb_is_nonlinear(skb)) 1435 - dptr = skb->data + dataoff; 1436 - else { 1285 + if (skb_is_nonlinear(skb)) { 1437 1286 pr_debug("Copy of skbuff not supported yet.\n"); 1438 1287 return NF_ACCEPT; 1439 1288 } 1440 1289 1290 + dptr = skb->data + dataoff; 1441 1291 datalen = skb->len - dataoff; 1442 1292 if (datalen < strlen("SIP/2.0 200")) 1443 1293 return NF_ACCEPT; 1444 1294 1445 - if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) 1446 - ret = process_sip_request(skb, dataoff, &dptr, &datalen); 1447 - else 1448 - ret = process_sip_response(skb, dataoff, &dptr, &datalen); 1449 - 1450 - if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { 1451 - nf_nat_sip = rcu_dereference(nf_nat_sip_hook); 1452 - if (nf_nat_sip && !nf_nat_sip(skb, dataoff, &dptr, &datalen)) 1453 - ret = NF_DROP; 1454 - } 1455 - 1456 - return ret; 1295 + return process_sip_msg(skb, ct, dataoff, &dptr, &datalen); 1457 1296 } 1458 1297 1459 - static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; 1460 - static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; 1298 + static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly; 1299 + static char sip_names[MAX_PORTS][4][sizeof("sip-65535")] __read_mostly; 1461 1300 1462 1301 static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { 1463 1302 [SIP_EXPECT_SIGNALLING] = { ··· 1470 1333 int i, j; 1471 1334 1472 1335 for (i = 0; i < ports_c; i++) { 1473 - for (j = 0; j < 2; j++) { 1336 + for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { 1474 1337 if (sip[i][j].me == NULL) 1475 1338 continue; 1476 1339 nf_conntrack_helper_unregister(&sip[i][j]); ··· 1490 1353 memset(&sip[i], 0, sizeof(sip[i])); 1491 1354 1492 1355 sip[i][0].tuple.src.l3num = AF_INET; 1493 - sip[i][1].tuple.src.l3num = AF_INET6; 1494 - for (j = 0; j < 2; j++) { 1495 - sip[i][j].tuple.dst.protonum = IPPROTO_UDP; 1356 + sip[i][0].tuple.dst.protonum = IPPROTO_UDP; 1357 + sip[i][0].help = sip_help_udp; 1358 + sip[i][1].tuple.src.l3num = AF_INET; 1359 + sip[i][1].tuple.dst.protonum = IPPROTO_TCP; 1360 + sip[i][1].help = sip_help_tcp; 1361 + 1362 + sip[i][2].tuple.src.l3num = AF_INET6; 1363 + sip[i][2].tuple.dst.protonum = IPPROTO_UDP; 1364 + sip[i][2].help = sip_help_udp; 1365 + sip[i][3].tuple.src.l3num = AF_INET6; 1366 + sip[i][3].tuple.dst.protonum = IPPROTO_TCP; 1367 + sip[i][3].help = sip_help_tcp; 1368 + 1369 + for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { 1496 1370 sip[i][j].tuple.src.u.udp.port = htons(ports[i]); 1497 1371 sip[i][j].expect_policy = sip_exp_policy; 1498 1372 sip[i][j].expect_class_max = SIP_EXPECT_MAX; 1499 1373 sip[i][j].me = THIS_MODULE; 1500 - sip[i][j].help = sip_help; 1501 1374 1502 1375 tmpname = &sip_names[i][j][0]; 1503 1376 if (ports[i] == SIP_PORT)