diff options
author | Patrick McHardy <kaber@trash.net> | 2013-08-27 02:50:12 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-08-27 18:26:48 -0400 |
commit | 41d73ec053d2424599c4ed8452b889374d523ade (patch) | |
tree | 404e0418e7f4c06cd37065eee97f67f6123df160 /net/netfilter | |
parent | 706f5151e349a3d8ab85237d0d6c553930376e9f (diff) |
netfilter: nf_conntrack: make sequence number adjustments usuable without NAT
Split out sequence number adjustments from NAT and move them to the conntrack
core to make them usable for SYN proxying. The sequence number adjustment
information is moved to a seperate extend. The extend is added to new
conntracks when a NAT mapping is set up for a connection using a helper.
As a side effect, this saves 24 bytes per connection with NAT in the common
case that a connection does not have a helper assigned.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Tested-by: Martin Topholm <mph@one.com>
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/Makefile | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 16 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 115 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 18 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_seqadj.c | 218 | ||||
-rw-r--r-- | net/netfilter/nf_nat_core.c | 16 | ||||
-rw-r--r-- | net/netfilter/nf_nat_helper.c | 228 | ||||
-rw-r--r-- | net/netfilter/nf_nat_sip.c | 3 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue_ct.c | 8 |
9 files changed, 296 insertions, 328 deletions
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index ebfa7dc747cd..89a9c1658f5e 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o | 1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o |
2 | 2 | ||
3 | nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o | 3 | nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o nf_conntrack_seqadj.o |
4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o | 4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o |
5 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o | 5 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o |
6 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o | 6 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index da6f1787a102..00a7a94d4132 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <net/netfilter/nf_conntrack_l4proto.h> | 39 | #include <net/netfilter/nf_conntrack_l4proto.h> |
40 | #include <net/netfilter/nf_conntrack_expect.h> | 40 | #include <net/netfilter/nf_conntrack_expect.h> |
41 | #include <net/netfilter/nf_conntrack_helper.h> | 41 | #include <net/netfilter/nf_conntrack_helper.h> |
42 | #include <net/netfilter/nf_conntrack_seqadj.h> | ||
42 | #include <net/netfilter/nf_conntrack_core.h> | 43 | #include <net/netfilter/nf_conntrack_core.h> |
43 | #include <net/netfilter/nf_conntrack_extend.h> | 44 | #include <net/netfilter/nf_conntrack_extend.h> |
44 | #include <net/netfilter/nf_conntrack_acct.h> | 45 | #include <net/netfilter/nf_conntrack_acct.h> |
@@ -1326,6 +1327,7 @@ void nf_conntrack_cleanup_end(void) | |||
1326 | nf_ct_extend_unregister(&nf_ct_zone_extend); | 1327 | nf_ct_extend_unregister(&nf_ct_zone_extend); |
1327 | #endif | 1328 | #endif |
1328 | nf_conntrack_proto_fini(); | 1329 | nf_conntrack_proto_fini(); |
1330 | nf_conntrack_seqadj_fini(); | ||
1329 | nf_conntrack_labels_fini(); | 1331 | nf_conntrack_labels_fini(); |
1330 | nf_conntrack_helper_fini(); | 1332 | nf_conntrack_helper_fini(); |
1331 | nf_conntrack_timeout_fini(); | 1333 | nf_conntrack_timeout_fini(); |
@@ -1531,6 +1533,10 @@ int nf_conntrack_init_start(void) | |||
1531 | if (ret < 0) | 1533 | if (ret < 0) |
1532 | goto err_labels; | 1534 | goto err_labels; |
1533 | 1535 | ||
1536 | ret = nf_conntrack_seqadj_init(); | ||
1537 | if (ret < 0) | ||
1538 | goto err_seqadj; | ||
1539 | |||
1534 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 1540 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
1535 | ret = nf_ct_extend_register(&nf_ct_zone_extend); | 1541 | ret = nf_ct_extend_register(&nf_ct_zone_extend); |
1536 | if (ret < 0) | 1542 | if (ret < 0) |
@@ -1555,6 +1561,8 @@ err_proto: | |||
1555 | nf_ct_extend_unregister(&nf_ct_zone_extend); | 1561 | nf_ct_extend_unregister(&nf_ct_zone_extend); |
1556 | err_extend: | 1562 | err_extend: |
1557 | #endif | 1563 | #endif |
1564 | nf_conntrack_seqadj_fini(); | ||
1565 | err_seqadj: | ||
1558 | nf_conntrack_labels_fini(); | 1566 | nf_conntrack_labels_fini(); |
1559 | err_labels: | 1567 | err_labels: |
1560 | nf_conntrack_helper_fini(); | 1568 | nf_conntrack_helper_fini(); |
@@ -1577,9 +1585,6 @@ void nf_conntrack_init_end(void) | |||
1577 | /* For use by REJECT target */ | 1585 | /* For use by REJECT target */ |
1578 | RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); | 1586 | RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); |
1579 | RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); | 1587 | RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); |
1580 | |||
1581 | /* Howto get NAT offsets */ | ||
1582 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | ||
1583 | } | 1588 | } |
1584 | 1589 | ||
1585 | /* | 1590 | /* |
@@ -1666,8 +1671,3 @@ err_slabname: | |||
1666 | err_stat: | 1671 | err_stat: |
1667 | return ret; | 1672 | return ret; |
1668 | } | 1673 | } |
1669 | |||
1670 | s32 (*nf_ct_nat_offset)(const struct nf_conn *ct, | ||
1671 | enum ip_conntrack_dir dir, | ||
1672 | u32 seq); | ||
1673 | EXPORT_SYMBOL_GPL(nf_ct_nat_offset); | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index fa61fea63234..7c55745ececf 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <net/netfilter/nf_conntrack_core.h> | 37 | #include <net/netfilter/nf_conntrack_core.h> |
38 | #include <net/netfilter/nf_conntrack_expect.h> | 38 | #include <net/netfilter/nf_conntrack_expect.h> |
39 | #include <net/netfilter/nf_conntrack_helper.h> | 39 | #include <net/netfilter/nf_conntrack_helper.h> |
40 | #include <net/netfilter/nf_conntrack_seqadj.h> | ||
40 | #include <net/netfilter/nf_conntrack_l3proto.h> | 41 | #include <net/netfilter/nf_conntrack_l3proto.h> |
41 | #include <net/netfilter/nf_conntrack_l4proto.h> | 42 | #include <net/netfilter/nf_conntrack_l4proto.h> |
42 | #include <net/netfilter/nf_conntrack_tuple.h> | 43 | #include <net/netfilter/nf_conntrack_tuple.h> |
@@ -381,9 +382,8 @@ nla_put_failure: | |||
381 | return -1; | 382 | return -1; |
382 | } | 383 | } |
383 | 384 | ||
384 | #ifdef CONFIG_NF_NAT_NEEDED | ||
385 | static int | 385 | static int |
386 | dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type) | 386 | dump_ct_seq_adj(struct sk_buff *skb, const struct nf_ct_seqadj *seq, int type) |
387 | { | 387 | { |
388 | struct nlattr *nest_parms; | 388 | struct nlattr *nest_parms; |
389 | 389 | ||
@@ -391,12 +391,12 @@ dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type) | |||
391 | if (!nest_parms) | 391 | if (!nest_parms) |
392 | goto nla_put_failure; | 392 | goto nla_put_failure; |
393 | 393 | ||
394 | if (nla_put_be32(skb, CTA_NAT_SEQ_CORRECTION_POS, | 394 | if (nla_put_be32(skb, CTA_SEQADJ_CORRECTION_POS, |
395 | htonl(natseq->correction_pos)) || | 395 | htonl(seq->correction_pos)) || |
396 | nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_BEFORE, | 396 | nla_put_be32(skb, CTA_SEQADJ_OFFSET_BEFORE, |
397 | htonl(natseq->offset_before)) || | 397 | htonl(seq->offset_before)) || |
398 | nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_AFTER, | 398 | nla_put_be32(skb, CTA_SEQADJ_OFFSET_AFTER, |
399 | htonl(natseq->offset_after))) | 399 | htonl(seq->offset_after))) |
400 | goto nla_put_failure; | 400 | goto nla_put_failure; |
401 | 401 | ||
402 | nla_nest_end(skb, nest_parms); | 402 | nla_nest_end(skb, nest_parms); |
@@ -408,27 +408,24 @@ nla_put_failure: | |||
408 | } | 408 | } |
409 | 409 | ||
410 | static inline int | 410 | static inline int |
411 | ctnetlink_dump_nat_seq_adj(struct sk_buff *skb, const struct nf_conn *ct) | 411 | ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, const struct nf_conn *ct) |
412 | { | 412 | { |
413 | struct nf_nat_seq *natseq; | 413 | struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); |
414 | struct nf_conn_nat *nat = nfct_nat(ct); | 414 | struct nf_ct_seqadj *seq; |
415 | 415 | ||
416 | if (!(ct->status & IPS_SEQ_ADJUST) || !nat) | 416 | if (!(ct->status & IPS_SEQ_ADJUST) || !seqadj) |
417 | return 0; | 417 | return 0; |
418 | 418 | ||
419 | natseq = &nat->seq[IP_CT_DIR_ORIGINAL]; | 419 | seq = &seqadj->seq[IP_CT_DIR_ORIGINAL]; |
420 | if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_ORIG) == -1) | 420 | if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_ORIG) == -1) |
421 | return -1; | 421 | return -1; |
422 | 422 | ||
423 | natseq = &nat->seq[IP_CT_DIR_REPLY]; | 423 | seq = &seqadj->seq[IP_CT_DIR_REPLY]; |
424 | if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_REPLY) == -1) | 424 | if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_REPLY) == -1) |
425 | return -1; | 425 | return -1; |
426 | 426 | ||
427 | return 0; | 427 | return 0; |
428 | } | 428 | } |
429 | #else | ||
430 | #define ctnetlink_dump_nat_seq_adj(a, b) (0) | ||
431 | #endif | ||
432 | 429 | ||
433 | static inline int | 430 | static inline int |
434 | ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) | 431 | ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) |
@@ -502,7 +499,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, | |||
502 | ctnetlink_dump_id(skb, ct) < 0 || | 499 | ctnetlink_dump_id(skb, ct) < 0 || |
503 | ctnetlink_dump_use(skb, ct) < 0 || | 500 | ctnetlink_dump_use(skb, ct) < 0 || |
504 | ctnetlink_dump_master(skb, ct) < 0 || | 501 | ctnetlink_dump_master(skb, ct) < 0 || |
505 | ctnetlink_dump_nat_seq_adj(skb, ct) < 0) | 502 | ctnetlink_dump_ct_seq_adj(skb, ct) < 0) |
506 | goto nla_put_failure; | 503 | goto nla_put_failure; |
507 | 504 | ||
508 | nlmsg_end(skb, nlh); | 505 | nlmsg_end(skb, nlh); |
@@ -707,8 +704,8 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) | |||
707 | ctnetlink_dump_master(skb, ct) < 0) | 704 | ctnetlink_dump_master(skb, ct) < 0) |
708 | goto nla_put_failure; | 705 | goto nla_put_failure; |
709 | 706 | ||
710 | if (events & (1 << IPCT_NATSEQADJ) && | 707 | if (events & (1 << IPCT_SEQADJ) && |
711 | ctnetlink_dump_nat_seq_adj(skb, ct) < 0) | 708 | ctnetlink_dump_ct_seq_adj(skb, ct) < 0) |
712 | goto nla_put_failure; | 709 | goto nla_put_failure; |
713 | } | 710 | } |
714 | 711 | ||
@@ -1439,66 +1436,65 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, const struct nlattr * const cda[] | |||
1439 | return err; | 1436 | return err; |
1440 | } | 1437 | } |
1441 | 1438 | ||
1442 | #ifdef CONFIG_NF_NAT_NEEDED | 1439 | static const struct nla_policy seqadj_policy[CTA_SEQADJ_MAX+1] = { |
1443 | static const struct nla_policy nat_seq_policy[CTA_NAT_SEQ_MAX+1] = { | 1440 | [CTA_SEQADJ_CORRECTION_POS] = { .type = NLA_U32 }, |
1444 | [CTA_NAT_SEQ_CORRECTION_POS] = { .type = NLA_U32 }, | 1441 | [CTA_SEQADJ_OFFSET_BEFORE] = { .type = NLA_U32 }, |
1445 | [CTA_NAT_SEQ_OFFSET_BEFORE] = { .type = NLA_U32 }, | 1442 | [CTA_SEQADJ_OFFSET_AFTER] = { .type = NLA_U32 }, |
1446 | [CTA_NAT_SEQ_OFFSET_AFTER] = { .type = NLA_U32 }, | ||
1447 | }; | 1443 | }; |
1448 | 1444 | ||
1449 | static inline int | 1445 | static inline int |
1450 | change_nat_seq_adj(struct nf_nat_seq *natseq, const struct nlattr * const attr) | 1446 | change_seq_adj(struct nf_ct_seqadj *seq, const struct nlattr * const attr) |
1451 | { | 1447 | { |
1452 | int err; | 1448 | int err; |
1453 | struct nlattr *cda[CTA_NAT_SEQ_MAX+1]; | 1449 | struct nlattr *cda[CTA_SEQADJ_MAX+1]; |
1454 | 1450 | ||
1455 | err = nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, nat_seq_policy); | 1451 | err = nla_parse_nested(cda, CTA_SEQADJ_MAX, attr, seqadj_policy); |
1456 | if (err < 0) | 1452 | if (err < 0) |
1457 | return err; | 1453 | return err; |
1458 | 1454 | ||
1459 | if (!cda[CTA_NAT_SEQ_CORRECTION_POS]) | 1455 | if (!cda[CTA_SEQADJ_CORRECTION_POS]) |
1460 | return -EINVAL; | 1456 | return -EINVAL; |
1461 | 1457 | ||
1462 | natseq->correction_pos = | 1458 | seq->correction_pos = |
1463 | ntohl(nla_get_be32(cda[CTA_NAT_SEQ_CORRECTION_POS])); | 1459 | ntohl(nla_get_be32(cda[CTA_SEQADJ_CORRECTION_POS])); |
1464 | 1460 | ||
1465 | if (!cda[CTA_NAT_SEQ_OFFSET_BEFORE]) | 1461 | if (!cda[CTA_SEQADJ_OFFSET_BEFORE]) |
1466 | return -EINVAL; | 1462 | return -EINVAL; |
1467 | 1463 | ||
1468 | natseq->offset_before = | 1464 | seq->offset_before = |
1469 | ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_BEFORE])); | 1465 | ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_BEFORE])); |
1470 | 1466 | ||
1471 | if (!cda[CTA_NAT_SEQ_OFFSET_AFTER]) | 1467 | if (!cda[CTA_SEQADJ_OFFSET_AFTER]) |
1472 | return -EINVAL; | 1468 | return -EINVAL; |
1473 | 1469 | ||
1474 | natseq->offset_after = | 1470 | seq->offset_after = |
1475 | ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_AFTER])); | 1471 | ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_AFTER])); |
1476 | 1472 | ||
1477 | return 0; | 1473 | return 0; |
1478 | } | 1474 | } |
1479 | 1475 | ||
1480 | static int | 1476 | static int |
1481 | ctnetlink_change_nat_seq_adj(struct nf_conn *ct, | 1477 | ctnetlink_change_seq_adj(struct nf_conn *ct, |
1482 | const struct nlattr * const cda[]) | 1478 | const struct nlattr * const cda[]) |
1483 | { | 1479 | { |
1480 | struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); | ||
1484 | int ret = 0; | 1481 | int ret = 0; |
1485 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
1486 | 1482 | ||
1487 | if (!nat) | 1483 | if (!seqadj) |
1488 | return 0; | 1484 | return 0; |
1489 | 1485 | ||
1490 | if (cda[CTA_NAT_SEQ_ADJ_ORIG]) { | 1486 | if (cda[CTA_SEQ_ADJ_ORIG]) { |
1491 | ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_ORIGINAL], | 1487 | ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_ORIGINAL], |
1492 | cda[CTA_NAT_SEQ_ADJ_ORIG]); | 1488 | cda[CTA_SEQ_ADJ_ORIG]); |
1493 | if (ret < 0) | 1489 | if (ret < 0) |
1494 | return ret; | 1490 | return ret; |
1495 | 1491 | ||
1496 | ct->status |= IPS_SEQ_ADJUST; | 1492 | ct->status |= IPS_SEQ_ADJUST; |
1497 | } | 1493 | } |
1498 | 1494 | ||
1499 | if (cda[CTA_NAT_SEQ_ADJ_REPLY]) { | 1495 | if (cda[CTA_SEQ_ADJ_REPLY]) { |
1500 | ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_REPLY], | 1496 | ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_REPLY], |
1501 | cda[CTA_NAT_SEQ_ADJ_REPLY]); | 1497 | cda[CTA_SEQ_ADJ_REPLY]); |
1502 | if (ret < 0) | 1498 | if (ret < 0) |
1503 | return ret; | 1499 | return ret; |
1504 | 1500 | ||
@@ -1507,7 +1503,6 @@ ctnetlink_change_nat_seq_adj(struct nf_conn *ct, | |||
1507 | 1503 | ||
1508 | return 0; | 1504 | return 0; |
1509 | } | 1505 | } |
1510 | #endif | ||
1511 | 1506 | ||
1512 | static int | 1507 | static int |
1513 | ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) | 1508 | ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) |
@@ -1573,13 +1568,12 @@ ctnetlink_change_conntrack(struct nf_conn *ct, | |||
1573 | ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); | 1568 | ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); |
1574 | #endif | 1569 | #endif |
1575 | 1570 | ||
1576 | #ifdef CONFIG_NF_NAT_NEEDED | 1571 | if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) { |
1577 | if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { | 1572 | err = ctnetlink_change_seq_adj(ct, cda); |
1578 | err = ctnetlink_change_nat_seq_adj(ct, cda); | ||
1579 | if (err < 0) | 1573 | if (err < 0) |
1580 | return err; | 1574 | return err; |
1581 | } | 1575 | } |
1582 | #endif | 1576 | |
1583 | if (cda[CTA_LABELS]) { | 1577 | if (cda[CTA_LABELS]) { |
1584 | err = ctnetlink_attach_labels(ct, cda); | 1578 | err = ctnetlink_attach_labels(ct, cda); |
1585 | if (err < 0) | 1579 | if (err < 0) |
@@ -1684,13 +1678,11 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, | |||
1684 | goto err2; | 1678 | goto err2; |
1685 | } | 1679 | } |
1686 | 1680 | ||
1687 | #ifdef CONFIG_NF_NAT_NEEDED | 1681 | if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) { |
1688 | if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { | 1682 | err = ctnetlink_change_seq_adj(ct, cda); |
1689 | err = ctnetlink_change_nat_seq_adj(ct, cda); | ||
1690 | if (err < 0) | 1683 | if (err < 0) |
1691 | goto err2; | 1684 | goto err2; |
1692 | } | 1685 | } |
1693 | #endif | ||
1694 | 1686 | ||
1695 | memset(&ct->proto, 0, sizeof(ct->proto)); | 1687 | memset(&ct->proto, 0, sizeof(ct->proto)); |
1696 | if (cda[CTA_PROTOINFO]) { | 1688 | if (cda[CTA_PROTOINFO]) { |
@@ -1804,7 +1796,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1804 | (1 << IPCT_ASSURED) | | 1796 | (1 << IPCT_ASSURED) | |
1805 | (1 << IPCT_HELPER) | | 1797 | (1 << IPCT_HELPER) | |
1806 | (1 << IPCT_PROTOINFO) | | 1798 | (1 << IPCT_PROTOINFO) | |
1807 | (1 << IPCT_NATSEQADJ) | | 1799 | (1 << IPCT_SEQADJ) | |
1808 | (1 << IPCT_MARK) | events, | 1800 | (1 << IPCT_MARK) | events, |
1809 | ct, NETLINK_CB(skb).portid, | 1801 | ct, NETLINK_CB(skb).portid, |
1810 | nlmsg_report(nlh)); | 1802 | nlmsg_report(nlh)); |
@@ -1827,7 +1819,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1827 | (1 << IPCT_HELPER) | | 1819 | (1 << IPCT_HELPER) | |
1828 | (1 << IPCT_LABEL) | | 1820 | (1 << IPCT_LABEL) | |
1829 | (1 << IPCT_PROTOINFO) | | 1821 | (1 << IPCT_PROTOINFO) | |
1830 | (1 << IPCT_NATSEQADJ) | | 1822 | (1 << IPCT_SEQADJ) | |
1831 | (1 << IPCT_MARK), | 1823 | (1 << IPCT_MARK), |
1832 | ct, NETLINK_CB(skb).portid, | 1824 | ct, NETLINK_CB(skb).portid, |
1833 | nlmsg_report(nlh)); | 1825 | nlmsg_report(nlh)); |
@@ -2082,7 +2074,7 @@ ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct) | |||
2082 | goto nla_put_failure; | 2074 | goto nla_put_failure; |
2083 | 2075 | ||
2084 | if ((ct->status & IPS_SEQ_ADJUST) && | 2076 | if ((ct->status & IPS_SEQ_ADJUST) && |
2085 | ctnetlink_dump_nat_seq_adj(skb, ct) < 0) | 2077 | ctnetlink_dump_ct_seq_adj(skb, ct) < 0) |
2086 | goto nla_put_failure; | 2078 | goto nla_put_failure; |
2087 | 2079 | ||
2088 | #ifdef CONFIG_NF_CONNTRACK_MARK | 2080 | #ifdef CONFIG_NF_CONNTRACK_MARK |
@@ -2211,6 +2203,7 @@ static struct nfq_ct_hook ctnetlink_nfqueue_hook = { | |||
2211 | .build = ctnetlink_nfqueue_build, | 2203 | .build = ctnetlink_nfqueue_build, |
2212 | .parse = ctnetlink_nfqueue_parse, | 2204 | .parse = ctnetlink_nfqueue_parse, |
2213 | .attach_expect = ctnetlink_nfqueue_attach_expect, | 2205 | .attach_expect = ctnetlink_nfqueue_attach_expect, |
2206 | .seq_adjust = nf_ct_tcp_seqadj_set, | ||
2214 | }; | 2207 | }; |
2215 | #endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */ | 2208 | #endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */ |
2216 | 2209 | ||
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index d224e001f14f..984a8d1a3359 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <net/netfilter/nf_conntrack.h> | 27 | #include <net/netfilter/nf_conntrack.h> |
28 | #include <net/netfilter/nf_conntrack_l4proto.h> | 28 | #include <net/netfilter/nf_conntrack_l4proto.h> |
29 | #include <net/netfilter/nf_conntrack_ecache.h> | 29 | #include <net/netfilter/nf_conntrack_ecache.h> |
30 | #include <net/netfilter/nf_conntrack_seqadj.h> | ||
30 | #include <net/netfilter/nf_log.h> | 31 | #include <net/netfilter/nf_log.h> |
31 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 32 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
32 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 33 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
@@ -495,21 +496,6 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff, | |||
495 | } | 496 | } |
496 | } | 497 | } |
497 | 498 | ||
498 | #ifdef CONFIG_NF_NAT_NEEDED | ||
499 | static inline s32 nat_offset(const struct nf_conn *ct, | ||
500 | enum ip_conntrack_dir dir, | ||
501 | u32 seq) | ||
502 | { | ||
503 | typeof(nf_ct_nat_offset) get_offset = rcu_dereference(nf_ct_nat_offset); | ||
504 | |||
505 | return get_offset != NULL ? get_offset(ct, dir, seq) : 0; | ||
506 | } | ||
507 | #define NAT_OFFSET(ct, dir, seq) \ | ||
508 | (nat_offset(ct, dir, seq)) | ||
509 | #else | ||
510 | #define NAT_OFFSET(ct, dir, seq) 0 | ||
511 | #endif | ||
512 | |||
513 | static bool tcp_in_window(const struct nf_conn *ct, | 499 | static bool tcp_in_window(const struct nf_conn *ct, |
514 | struct ip_ct_tcp *state, | 500 | struct ip_ct_tcp *state, |
515 | enum ip_conntrack_dir dir, | 501 | enum ip_conntrack_dir dir, |
@@ -540,7 +526,7 @@ static bool tcp_in_window(const struct nf_conn *ct, | |||
540 | tcp_sack(skb, dataoff, tcph, &sack); | 526 | tcp_sack(skb, dataoff, tcph, &sack); |
541 | 527 | ||
542 | /* Take into account NAT sequence number mangling */ | 528 | /* Take into account NAT sequence number mangling */ |
543 | receiver_offset = NAT_OFFSET(ct, !dir, ack - 1); | 529 | receiver_offset = nf_ct_seq_offset(ct, !dir, ack - 1); |
544 | ack -= receiver_offset; | 530 | ack -= receiver_offset; |
545 | sack -= receiver_offset; | 531 | sack -= receiver_offset; |
546 | 532 | ||
diff --git a/net/netfilter/nf_conntrack_seqadj.c b/net/netfilter/nf_conntrack_seqadj.c new file mode 100644 index 000000000000..483eb9ce3216 --- /dev/null +++ b/net/netfilter/nf_conntrack_seqadj.c | |||
@@ -0,0 +1,218 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/netfilter.h> | ||
3 | #include <net/tcp.h> | ||
4 | |||
5 | #include <net/netfilter/nf_conntrack.h> | ||
6 | #include <net/netfilter/nf_conntrack_extend.h> | ||
7 | #include <net/netfilter/nf_conntrack_seqadj.h> | ||
8 | |||
9 | int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo, | ||
10 | __be32 seq, s32 off) | ||
11 | { | ||
12 | struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); | ||
13 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
14 | struct nf_ct_seqadj *this_way; | ||
15 | |||
16 | if (off == 0) | ||
17 | return 0; | ||
18 | |||
19 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); | ||
20 | |||
21 | spin_lock_bh(&ct->lock); | ||
22 | this_way = &seqadj->seq[dir]; | ||
23 | if (this_way->offset_before == this_way->offset_after || | ||
24 | before(this_way->correction_pos, seq)) { | ||
25 | this_way->correction_pos = seq; | ||
26 | this_way->offset_before = this_way->offset_after; | ||
27 | this_way->offset_after += off; | ||
28 | } | ||
29 | spin_unlock_bh(&ct->lock); | ||
30 | return 0; | ||
31 | } | ||
32 | EXPORT_SYMBOL_GPL(nf_ct_seqadj_set); | ||
33 | |||
34 | void nf_ct_tcp_seqadj_set(struct sk_buff *skb, | ||
35 | struct nf_conn *ct, enum ip_conntrack_info ctinfo, | ||
36 | s32 off) | ||
37 | { | ||
38 | const struct tcphdr *th; | ||
39 | |||
40 | if (nf_ct_protonum(ct) != IPPROTO_TCP) | ||
41 | return; | ||
42 | |||
43 | th = (struct tcphdr *)(skb_network_header(skb) + ip_hdrlen(skb)); | ||
44 | nf_ct_seqadj_set(ct, ctinfo, th->seq, off); | ||
45 | } | ||
46 | EXPORT_SYMBOL_GPL(nf_ct_tcp_seqadj_set); | ||
47 | |||
48 | /* Adjust one found SACK option including checksum correction */ | ||
49 | static void nf_ct_sack_block_adjust(struct sk_buff *skb, | ||
50 | struct tcphdr *tcph, | ||
51 | unsigned int sackoff, | ||
52 | unsigned int sackend, | ||
53 | struct nf_ct_seqadj *seq) | ||
54 | { | ||
55 | while (sackoff < sackend) { | ||
56 | struct tcp_sack_block_wire *sack; | ||
57 | __be32 new_start_seq, new_end_seq; | ||
58 | |||
59 | sack = (void *)skb->data + sackoff; | ||
60 | if (after(ntohl(sack->start_seq) - seq->offset_before, | ||
61 | seq->correction_pos)) | ||
62 | new_start_seq = htonl(ntohl(sack->start_seq) - | ||
63 | seq->offset_after); | ||
64 | else | ||
65 | new_start_seq = htonl(ntohl(sack->start_seq) - | ||
66 | seq->offset_before); | ||
67 | |||
68 | if (after(ntohl(sack->end_seq) - seq->offset_before, | ||
69 | seq->correction_pos)) | ||
70 | new_end_seq = htonl(ntohl(sack->end_seq) - | ||
71 | seq->offset_after); | ||
72 | else | ||
73 | new_end_seq = htonl(ntohl(sack->end_seq) - | ||
74 | seq->offset_before); | ||
75 | |||
76 | pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", | ||
77 | ntohl(sack->start_seq), new_start_seq, | ||
78 | ntohl(sack->end_seq), new_end_seq); | ||
79 | |||
80 | inet_proto_csum_replace4(&tcph->check, skb, | ||
81 | sack->start_seq, new_start_seq, 0); | ||
82 | inet_proto_csum_replace4(&tcph->check, skb, | ||
83 | sack->end_seq, new_end_seq, 0); | ||
84 | sack->start_seq = new_start_seq; | ||
85 | sack->end_seq = new_end_seq; | ||
86 | sackoff += sizeof(*sack); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /* TCP SACK sequence number adjustment */ | ||
91 | static unsigned int nf_ct_sack_adjust(struct sk_buff *skb, | ||
92 | unsigned int protoff, | ||
93 | struct tcphdr *tcph, | ||
94 | struct nf_conn *ct, | ||
95 | enum ip_conntrack_info ctinfo) | ||
96 | { | ||
97 | unsigned int dir, optoff, optend; | ||
98 | struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); | ||
99 | |||
100 | optoff = protoff + sizeof(struct tcphdr); | ||
101 | optend = protoff + tcph->doff * 4; | ||
102 | |||
103 | if (!skb_make_writable(skb, optend)) | ||
104 | return 0; | ||
105 | |||
106 | dir = CTINFO2DIR(ctinfo); | ||
107 | |||
108 | while (optoff < optend) { | ||
109 | /* Usually: option, length. */ | ||
110 | unsigned char *op = skb->data + optoff; | ||
111 | |||
112 | switch (op[0]) { | ||
113 | case TCPOPT_EOL: | ||
114 | return 1; | ||
115 | case TCPOPT_NOP: | ||
116 | optoff++; | ||
117 | continue; | ||
118 | default: | ||
119 | /* no partial options */ | ||
120 | if (optoff + 1 == optend || | ||
121 | optoff + op[1] > optend || | ||
122 | op[1] < 2) | ||
123 | return 0; | ||
124 | if (op[0] == TCPOPT_SACK && | ||
125 | op[1] >= 2+TCPOLEN_SACK_PERBLOCK && | ||
126 | ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) | ||
127 | nf_ct_sack_block_adjust(skb, tcph, optoff + 2, | ||
128 | optoff+op[1], | ||
129 | &seqadj->seq[!dir]); | ||
130 | optoff += op[1]; | ||
131 | } | ||
132 | } | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ | ||
137 | int nf_ct_seq_adjust(struct sk_buff *skb, | ||
138 | struct nf_conn *ct, enum ip_conntrack_info ctinfo, | ||
139 | unsigned int protoff) | ||
140 | { | ||
141 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
142 | struct tcphdr *tcph; | ||
143 | __be32 newseq, newack; | ||
144 | s32 seqoff, ackoff; | ||
145 | struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); | ||
146 | struct nf_ct_seqadj *this_way, *other_way; | ||
147 | int res; | ||
148 | |||
149 | this_way = &seqadj->seq[dir]; | ||
150 | other_way = &seqadj->seq[!dir]; | ||
151 | |||
152 | if (!skb_make_writable(skb, protoff + sizeof(*tcph))) | ||
153 | return 0; | ||
154 | |||
155 | tcph = (void *)skb->data + protoff; | ||
156 | spin_lock_bh(&ct->lock); | ||
157 | if (after(ntohl(tcph->seq), this_way->correction_pos)) | ||
158 | seqoff = this_way->offset_after; | ||
159 | else | ||
160 | seqoff = this_way->offset_before; | ||
161 | |||
162 | if (after(ntohl(tcph->ack_seq) - other_way->offset_before, | ||
163 | other_way->correction_pos)) | ||
164 | ackoff = other_way->offset_after; | ||
165 | else | ||
166 | ackoff = other_way->offset_before; | ||
167 | |||
168 | newseq = htonl(ntohl(tcph->seq) + seqoff); | ||
169 | newack = htonl(ntohl(tcph->ack_seq) - ackoff); | ||
170 | |||
171 | inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0); | ||
172 | inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0); | ||
173 | |||
174 | pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n", | ||
175 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), | ||
176 | ntohl(newack)); | ||
177 | |||
178 | tcph->seq = newseq; | ||
179 | tcph->ack_seq = newack; | ||
180 | |||
181 | res = nf_ct_sack_adjust(skb, protoff, tcph, ct, ctinfo); | ||
182 | spin_unlock_bh(&ct->lock); | ||
183 | |||
184 | return res; | ||
185 | } | ||
186 | EXPORT_SYMBOL_GPL(nf_ct_seq_adjust); | ||
187 | |||
188 | s32 nf_ct_seq_offset(const struct nf_conn *ct, | ||
189 | enum ip_conntrack_dir dir, | ||
190 | u32 seq) | ||
191 | { | ||
192 | struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); | ||
193 | struct nf_ct_seqadj *this_way; | ||
194 | |||
195 | if (!seqadj) | ||
196 | return 0; | ||
197 | |||
198 | this_way = &seqadj->seq[dir]; | ||
199 | return after(seq, this_way->correction_pos) ? | ||
200 | this_way->offset_after : this_way->offset_before; | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(nf_ct_seq_offset); | ||
203 | |||
204 | static struct nf_ct_ext_type nf_ct_seqadj_extend __read_mostly = { | ||
205 | .len = sizeof(struct nf_conn_seqadj), | ||
206 | .align = __alignof__(struct nf_conn_seqadj), | ||
207 | .id = NF_CT_EXT_SEQADJ, | ||
208 | }; | ||
209 | |||
210 | int nf_conntrack_seqadj_init(void) | ||
211 | { | ||
212 | return nf_ct_extend_register(&nf_ct_seqadj_extend); | ||
213 | } | ||
214 | |||
215 | void nf_conntrack_seqadj_fini(void) | ||
216 | { | ||
217 | nf_ct_extend_unregister(&nf_ct_seqadj_extend); | ||
218 | } | ||
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 6ff808375b5e..6f0f4f7f68a5 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <net/netfilter/nf_nat_core.h> | 25 | #include <net/netfilter/nf_nat_core.h> |
26 | #include <net/netfilter/nf_nat_helper.h> | 26 | #include <net/netfilter/nf_nat_helper.h> |
27 | #include <net/netfilter/nf_conntrack_helper.h> | 27 | #include <net/netfilter/nf_conntrack_helper.h> |
28 | #include <net/netfilter/nf_conntrack_seqadj.h> | ||
28 | #include <net/netfilter/nf_conntrack_l3proto.h> | 29 | #include <net/netfilter/nf_conntrack_l3proto.h> |
29 | #include <net/netfilter/nf_conntrack_zones.h> | 30 | #include <net/netfilter/nf_conntrack_zones.h> |
30 | #include <linux/netfilter/nf_nat.h> | 31 | #include <linux/netfilter/nf_nat.h> |
@@ -402,6 +403,9 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
402 | ct->status |= IPS_SRC_NAT; | 403 | ct->status |= IPS_SRC_NAT; |
403 | else | 404 | else |
404 | ct->status |= IPS_DST_NAT; | 405 | ct->status |= IPS_DST_NAT; |
406 | |||
407 | if (nfct_help(ct)) | ||
408 | nfct_seqadj_ext_add(ct); | ||
405 | } | 409 | } |
406 | 410 | ||
407 | if (maniptype == NF_NAT_MANIP_SRC) { | 411 | if (maniptype == NF_NAT_MANIP_SRC) { |
@@ -764,10 +768,6 @@ static struct nf_ct_helper_expectfn follow_master_nat = { | |||
764 | .expectfn = nf_nat_follow_master, | 768 | .expectfn = nf_nat_follow_master, |
765 | }; | 769 | }; |
766 | 770 | ||
767 | static struct nfq_ct_nat_hook nfq_ct_nat = { | ||
768 | .seq_adjust = nf_nat_tcp_seq_adjust, | ||
769 | }; | ||
770 | |||
771 | static int __init nf_nat_init(void) | 771 | static int __init nf_nat_init(void) |
772 | { | 772 | { |
773 | int ret; | 773 | int ret; |
@@ -787,14 +787,9 @@ static int __init nf_nat_init(void) | |||
787 | /* Initialize fake conntrack so that NAT will skip it */ | 787 | /* Initialize fake conntrack so that NAT will skip it */ |
788 | nf_ct_untracked_status_or(IPS_NAT_DONE_MASK); | 788 | nf_ct_untracked_status_or(IPS_NAT_DONE_MASK); |
789 | 789 | ||
790 | BUG_ON(nf_nat_seq_adjust_hook != NULL); | ||
791 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); | ||
792 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); | 790 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); |
793 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, | 791 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, |
794 | nfnetlink_parse_nat_setup); | 792 | nfnetlink_parse_nat_setup); |
795 | BUG_ON(nf_ct_nat_offset != NULL); | ||
796 | RCU_INIT_POINTER(nf_ct_nat_offset, nf_nat_get_offset); | ||
797 | RCU_INIT_POINTER(nfq_ct_nat_hook, &nfq_ct_nat); | ||
798 | #ifdef CONFIG_XFRM | 793 | #ifdef CONFIG_XFRM |
799 | BUG_ON(nf_nat_decode_session_hook != NULL); | 794 | BUG_ON(nf_nat_decode_session_hook != NULL); |
800 | RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session); | 795 | RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session); |
@@ -813,10 +808,7 @@ static void __exit nf_nat_cleanup(void) | |||
813 | unregister_pernet_subsys(&nf_nat_net_ops); | 808 | unregister_pernet_subsys(&nf_nat_net_ops); |
814 | nf_ct_extend_unregister(&nat_extend); | 809 | nf_ct_extend_unregister(&nat_extend); |
815 | nf_ct_helper_expectfn_unregister(&follow_master_nat); | 810 | nf_ct_helper_expectfn_unregister(&follow_master_nat); |
816 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); | ||
817 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); | 811 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); |
818 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | ||
819 | RCU_INIT_POINTER(nfq_ct_nat_hook, NULL); | ||
820 | #ifdef CONFIG_XFRM | 812 | #ifdef CONFIG_XFRM |
821 | RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); | 813 | RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); |
822 | #endif | 814 | #endif |
diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c index 46b9baa845a6..2840abb5bb99 100644 --- a/net/netfilter/nf_nat_helper.c +++ b/net/netfilter/nf_nat_helper.c | |||
@@ -20,67 +20,13 @@ | |||
20 | #include <net/netfilter/nf_conntrack_helper.h> | 20 | #include <net/netfilter/nf_conntrack_helper.h> |
21 | #include <net/netfilter/nf_conntrack_ecache.h> | 21 | #include <net/netfilter/nf_conntrack_ecache.h> |
22 | #include <net/netfilter/nf_conntrack_expect.h> | 22 | #include <net/netfilter/nf_conntrack_expect.h> |
23 | #include <net/netfilter/nf_conntrack_seqadj.h> | ||
23 | #include <net/netfilter/nf_nat.h> | 24 | #include <net/netfilter/nf_nat.h> |
24 | #include <net/netfilter/nf_nat_l3proto.h> | 25 | #include <net/netfilter/nf_nat_l3proto.h> |
25 | #include <net/netfilter/nf_nat_l4proto.h> | 26 | #include <net/netfilter/nf_nat_l4proto.h> |
26 | #include <net/netfilter/nf_nat_core.h> | 27 | #include <net/netfilter/nf_nat_core.h> |
27 | #include <net/netfilter/nf_nat_helper.h> | 28 | #include <net/netfilter/nf_nat_helper.h> |
28 | 29 | ||
29 | #define DUMP_OFFSET(x) \ | ||
30 | pr_debug("offset_before=%d, offset_after=%d, correction_pos=%u\n", \ | ||
31 | x->offset_before, x->offset_after, x->correction_pos); | ||
32 | |||
33 | /* Setup TCP sequence correction given this change at this sequence */ | ||
34 | static inline void | ||
35 | adjust_tcp_sequence(u32 seq, | ||
36 | int sizediff, | ||
37 | struct nf_conn *ct, | ||
38 | enum ip_conntrack_info ctinfo) | ||
39 | { | ||
40 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
41 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
42 | struct nf_nat_seq *this_way = &nat->seq[dir]; | ||
43 | |||
44 | pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n", | ||
45 | seq, sizediff); | ||
46 | |||
47 | pr_debug("adjust_tcp_sequence: Seq_offset before: "); | ||
48 | DUMP_OFFSET(this_way); | ||
49 | |||
50 | spin_lock_bh(&ct->lock); | ||
51 | |||
52 | /* SYN adjust. If it's uninitialized, or this is after last | ||
53 | * correction, record it: we don't handle more than one | ||
54 | * adjustment in the window, but do deal with common case of a | ||
55 | * retransmit */ | ||
56 | if (this_way->offset_before == this_way->offset_after || | ||
57 | before(this_way->correction_pos, seq)) { | ||
58 | this_way->correction_pos = seq; | ||
59 | this_way->offset_before = this_way->offset_after; | ||
60 | this_way->offset_after += sizediff; | ||
61 | } | ||
62 | spin_unlock_bh(&ct->lock); | ||
63 | |||
64 | pr_debug("adjust_tcp_sequence: Seq_offset after: "); | ||
65 | DUMP_OFFSET(this_way); | ||
66 | } | ||
67 | |||
68 | /* Get the offset value, for conntrack. Caller must have the conntrack locked */ | ||
69 | s32 nf_nat_get_offset(const struct nf_conn *ct, | ||
70 | enum ip_conntrack_dir dir, | ||
71 | u32 seq) | ||
72 | { | ||
73 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
74 | struct nf_nat_seq *this_way; | ||
75 | |||
76 | if (!nat) | ||
77 | return 0; | ||
78 | |||
79 | this_way = &nat->seq[dir]; | ||
80 | return after(seq, this_way->correction_pos) | ||
81 | ? this_way->offset_after : this_way->offset_before; | ||
82 | } | ||
83 | |||
84 | /* Frobs data inside this packet, which is linear. */ | 30 | /* Frobs data inside this packet, which is linear. */ |
85 | static void mangle_contents(struct sk_buff *skb, | 31 | static void mangle_contents(struct sk_buff *skb, |
86 | unsigned int dataoff, | 32 | unsigned int dataoff, |
@@ -135,30 +81,6 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra) | |||
135 | return 1; | 81 | return 1; |
136 | } | 82 | } |
137 | 83 | ||
138 | void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo, | ||
139 | __be32 seq, s32 off) | ||
140 | { | ||
141 | if (!off) | ||
142 | return; | ||
143 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); | ||
144 | adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo); | ||
145 | nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust); | ||
148 | |||
149 | void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, | ||
150 | u32 ctinfo, int off) | ||
151 | { | ||
152 | const struct tcphdr *th; | ||
153 | |||
154 | if (nf_ct_protonum(ct) != IPPROTO_TCP) | ||
155 | return; | ||
156 | |||
157 | th = (struct tcphdr *)(skb_network_header(skb)+ ip_hdrlen(skb)); | ||
158 | nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); | ||
159 | } | ||
160 | EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust); | ||
161 | |||
162 | /* Generic function for mangling variable-length address changes inside | 84 | /* Generic function for mangling variable-length address changes inside |
163 | * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX | 85 | * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX |
164 | * command in FTP). | 86 | * command in FTP). |
@@ -203,8 +125,8 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb, | |||
203 | datalen, oldlen); | 125 | datalen, oldlen); |
204 | 126 | ||
205 | if (adjust && rep_len != match_len) | 127 | if (adjust && rep_len != match_len) |
206 | nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq, | 128 | nf_ct_seqadj_set(ct, ctinfo, tcph->seq, |
207 | (int)rep_len - (int)match_len); | 129 | (int)rep_len - (int)match_len); |
208 | 130 | ||
209 | return 1; | 131 | return 1; |
210 | } | 132 | } |
@@ -264,150 +186,6 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb, | |||
264 | } | 186 | } |
265 | EXPORT_SYMBOL(nf_nat_mangle_udp_packet); | 187 | EXPORT_SYMBOL(nf_nat_mangle_udp_packet); |
266 | 188 | ||
267 | /* Adjust one found SACK option including checksum correction */ | ||
268 | static void | ||
269 | sack_adjust(struct sk_buff *skb, | ||
270 | struct tcphdr *tcph, | ||
271 | unsigned int sackoff, | ||
272 | unsigned int sackend, | ||
273 | struct nf_nat_seq *natseq) | ||
274 | { | ||
275 | while (sackoff < sackend) { | ||
276 | struct tcp_sack_block_wire *sack; | ||
277 | __be32 new_start_seq, new_end_seq; | ||
278 | |||
279 | sack = (void *)skb->data + sackoff; | ||
280 | if (after(ntohl(sack->start_seq) - natseq->offset_before, | ||
281 | natseq->correction_pos)) | ||
282 | new_start_seq = htonl(ntohl(sack->start_seq) | ||
283 | - natseq->offset_after); | ||
284 | else | ||
285 | new_start_seq = htonl(ntohl(sack->start_seq) | ||
286 | - natseq->offset_before); | ||
287 | |||
288 | if (after(ntohl(sack->end_seq) - natseq->offset_before, | ||
289 | natseq->correction_pos)) | ||
290 | new_end_seq = htonl(ntohl(sack->end_seq) | ||
291 | - natseq->offset_after); | ||
292 | else | ||
293 | new_end_seq = htonl(ntohl(sack->end_seq) | ||
294 | - natseq->offset_before); | ||
295 | |||
296 | pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", | ||
297 | ntohl(sack->start_seq), new_start_seq, | ||
298 | ntohl(sack->end_seq), new_end_seq); | ||
299 | |||
300 | inet_proto_csum_replace4(&tcph->check, skb, | ||
301 | sack->start_seq, new_start_seq, 0); | ||
302 | inet_proto_csum_replace4(&tcph->check, skb, | ||
303 | sack->end_seq, new_end_seq, 0); | ||
304 | sack->start_seq = new_start_seq; | ||
305 | sack->end_seq = new_end_seq; | ||
306 | sackoff += sizeof(*sack); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | /* TCP SACK sequence number adjustment */ | ||
311 | static inline unsigned int | ||
312 | nf_nat_sack_adjust(struct sk_buff *skb, | ||
313 | unsigned int protoff, | ||
314 | struct tcphdr *tcph, | ||
315 | struct nf_conn *ct, | ||
316 | enum ip_conntrack_info ctinfo) | ||
317 | { | ||
318 | unsigned int dir, optoff, optend; | ||
319 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
320 | |||
321 | optoff = protoff + sizeof(struct tcphdr); | ||
322 | optend = protoff + tcph->doff * 4; | ||
323 | |||
324 | if (!skb_make_writable(skb, optend)) | ||
325 | return 0; | ||
326 | |||
327 | dir = CTINFO2DIR(ctinfo); | ||
328 | |||
329 | while (optoff < optend) { | ||
330 | /* Usually: option, length. */ | ||
331 | unsigned char *op = skb->data + optoff; | ||
332 | |||
333 | switch (op[0]) { | ||
334 | case TCPOPT_EOL: | ||
335 | return 1; | ||
336 | case TCPOPT_NOP: | ||
337 | optoff++; | ||
338 | continue; | ||
339 | default: | ||
340 | /* no partial options */ | ||
341 | if (optoff + 1 == optend || | ||
342 | optoff + op[1] > optend || | ||
343 | op[1] < 2) | ||
344 | return 0; | ||
345 | if (op[0] == TCPOPT_SACK && | ||
346 | op[1] >= 2+TCPOLEN_SACK_PERBLOCK && | ||
347 | ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) | ||
348 | sack_adjust(skb, tcph, optoff+2, | ||
349 | optoff+op[1], &nat->seq[!dir]); | ||
350 | optoff += op[1]; | ||
351 | } | ||
352 | } | ||
353 | return 1; | ||
354 | } | ||
355 | |||
356 | /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ | ||
357 | int | ||
358 | nf_nat_seq_adjust(struct sk_buff *skb, | ||
359 | struct nf_conn *ct, | ||
360 | enum ip_conntrack_info ctinfo, | ||
361 | unsigned int protoff) | ||
362 | { | ||
363 | struct tcphdr *tcph; | ||
364 | int dir; | ||
365 | __be32 newseq, newack; | ||
366 | s32 seqoff, ackoff; | ||
367 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
368 | struct nf_nat_seq *this_way, *other_way; | ||
369 | int res; | ||
370 | |||
371 | dir = CTINFO2DIR(ctinfo); | ||
372 | |||
373 | this_way = &nat->seq[dir]; | ||
374 | other_way = &nat->seq[!dir]; | ||
375 | |||
376 | if (!skb_make_writable(skb, protoff + sizeof(*tcph))) | ||
377 | return 0; | ||
378 | |||
379 | tcph = (void *)skb->data + protoff; | ||
380 | spin_lock_bh(&ct->lock); | ||
381 | if (after(ntohl(tcph->seq), this_way->correction_pos)) | ||
382 | seqoff = this_way->offset_after; | ||
383 | else | ||
384 | seqoff = this_way->offset_before; | ||
385 | |||
386 | if (after(ntohl(tcph->ack_seq) - other_way->offset_before, | ||
387 | other_way->correction_pos)) | ||
388 | ackoff = other_way->offset_after; | ||
389 | else | ||
390 | ackoff = other_way->offset_before; | ||
391 | |||
392 | newseq = htonl(ntohl(tcph->seq) + seqoff); | ||
393 | newack = htonl(ntohl(tcph->ack_seq) - ackoff); | ||
394 | |||
395 | inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0); | ||
396 | inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0); | ||
397 | |||
398 | pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n", | ||
399 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), | ||
400 | ntohl(newack)); | ||
401 | |||
402 | tcph->seq = newseq; | ||
403 | tcph->ack_seq = newack; | ||
404 | |||
405 | res = nf_nat_sack_adjust(skb, protoff, tcph, ct, ctinfo); | ||
406 | spin_unlock_bh(&ct->lock); | ||
407 | |||
408 | return res; | ||
409 | } | ||
410 | |||
411 | /* Setup NAT on this expected conntrack so it follows master. */ | 189 | /* Setup NAT on this expected conntrack so it follows master. */ |
412 | /* If we fail to get a free NAT slot, we'll get dropped on confirm */ | 190 | /* If we fail to get a free NAT slot, we'll get dropped on confirm */ |
413 | void nf_nat_follow_master(struct nf_conn *ct, | 191 | void nf_nat_follow_master(struct nf_conn *ct, |
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c index dac11f73868e..f9790405b7ff 100644 --- a/net/netfilter/nf_nat_sip.c +++ b/net/netfilter/nf_nat_sip.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <net/netfilter/nf_nat_helper.h> | 20 | #include <net/netfilter/nf_nat_helper.h> |
21 | #include <net/netfilter/nf_conntrack_helper.h> | 21 | #include <net/netfilter/nf_conntrack_helper.h> |
22 | #include <net/netfilter/nf_conntrack_expect.h> | 22 | #include <net/netfilter/nf_conntrack_expect.h> |
23 | #include <net/netfilter/nf_conntrack_seqadj.h> | ||
23 | #include <linux/netfilter/nf_conntrack_sip.h> | 24 | #include <linux/netfilter/nf_conntrack_sip.h> |
24 | 25 | ||
25 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
@@ -308,7 +309,7 @@ static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff, | |||
308 | return; | 309 | return; |
309 | 310 | ||
310 | th = (struct tcphdr *)(skb->data + protoff); | 311 | th = (struct tcphdr *)(skb->data + protoff); |
311 | nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); | 312 | nf_ct_seqadj_set(ct, ctinfo, th->seq, off); |
312 | } | 313 | } |
313 | 314 | ||
314 | /* Handles expected signalling connections and media streams */ | 315 | /* Handles expected signalling connections and media streams */ |
diff --git a/net/netfilter/nfnetlink_queue_ct.c b/net/netfilter/nfnetlink_queue_ct.c index be893039966d..96cac50e0d12 100644 --- a/net/netfilter/nfnetlink_queue_ct.c +++ b/net/netfilter/nfnetlink_queue_ct.c | |||
@@ -87,14 +87,14 @@ nla_put_failure: | |||
87 | void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, | 87 | void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, |
88 | enum ip_conntrack_info ctinfo, int diff) | 88 | enum ip_conntrack_info ctinfo, int diff) |
89 | { | 89 | { |
90 | struct nfq_ct_nat_hook *nfq_nat_ct; | 90 | struct nfq_ct_hook *nfq_ct; |
91 | 91 | ||
92 | nfq_nat_ct = rcu_dereference(nfq_ct_nat_hook); | 92 | nfq_ct = rcu_dereference(nfq_ct_hook); |
93 | if (nfq_nat_ct == NULL) | 93 | if (nfq_ct == NULL) |
94 | return; | 94 | return; |
95 | 95 | ||
96 | if ((ct->status & IPS_NAT_MASK) && diff) | 96 | if ((ct->status & IPS_NAT_MASK) && diff) |
97 | nfq_nat_ct->seq_adjust(skb, ct, ctinfo, diff); | 97 | nfq_ct->seq_adjust(skb, ct, ctinfo, diff); |
98 | } | 98 | } |
99 | 99 | ||
100 | int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr, | 100 | int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr, |