aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2013-08-27 02:50:12 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2013-08-27 18:26:48 -0400
commit41d73ec053d2424599c4ed8452b889374d523ade (patch)
tree404e0418e7f4c06cd37065eee97f67f6123df160 /net/netfilter
parent706f5151e349a3d8ab85237d0d6c553930376e9f (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/Makefile2
-rw-r--r--net/netfilter/nf_conntrack_core.c16
-rw-r--r--net/netfilter/nf_conntrack_netlink.c115
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c18
-rw-r--r--net/netfilter/nf_conntrack_seqadj.c218
-rw-r--r--net/netfilter/nf_nat_core.c16
-rw-r--r--net/netfilter/nf_nat_helper.c228
-rw-r--r--net/netfilter/nf_nat_sip.c3
-rw-r--r--net/netfilter/nfnetlink_queue_ct.c8
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 @@
1netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o 1netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
2 2
3nf_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 3nf_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
4nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o 4nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
5nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o 5nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
6nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o 6nf_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);
1556err_extend: 1562err_extend:
1557#endif 1563#endif
1564 nf_conntrack_seqadj_fini();
1565err_seqadj:
1558 nf_conntrack_labels_fini(); 1566 nf_conntrack_labels_fini();
1559err_labels: 1567err_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:
1666err_stat: 1671err_stat:
1667 return ret; 1672 return ret;
1668} 1673}
1669
1670s32 (*nf_ct_nat_offset)(const struct nf_conn *ct,
1671 enum ip_conntrack_dir dir,
1672 u32 seq);
1673EXPORT_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
385static int 385static int
386dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type) 386dump_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
410static inline int 410static inline int
411ctnetlink_dump_nat_seq_adj(struct sk_buff *skb, const struct nf_conn *ct) 411ctnetlink_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
433static inline int 430static inline int
434ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) 431ctnetlink_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 1439static const struct nla_policy seqadj_policy[CTA_SEQADJ_MAX+1] = {
1443static 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
1449static inline int 1445static inline int
1450change_nat_seq_adj(struct nf_nat_seq *natseq, const struct nlattr * const attr) 1446change_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
1480static int 1476static int
1481ctnetlink_change_nat_seq_adj(struct nf_conn *ct, 1477ctnetlink_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
1512static int 1507static int
1513ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) 1508ctnetlink_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
499static 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
513static bool tcp_in_window(const struct nf_conn *ct, 499static 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
9int 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}
32EXPORT_SYMBOL_GPL(nf_ct_seqadj_set);
33
34void 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}
46EXPORT_SYMBOL_GPL(nf_ct_tcp_seqadj_set);
47
48/* Adjust one found SACK option including checksum correction */
49static 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 */
91static 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 */
137int 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}
186EXPORT_SYMBOL_GPL(nf_ct_seq_adjust);
187
188s32 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}
202EXPORT_SYMBOL_GPL(nf_ct_seq_offset);
203
204static 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
210int nf_conntrack_seqadj_init(void)
211{
212 return nf_ct_extend_register(&nf_ct_seqadj_extend);
213}
214
215void 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
767static struct nfq_ct_nat_hook nfq_ct_nat = {
768 .seq_adjust = nf_nat_tcp_seq_adjust,
769};
770
771static int __init nf_nat_init(void) 771static 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 */
34static inline void
35adjust_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 */
69s32 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. */
85static void mangle_contents(struct sk_buff *skb, 31static 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
138void 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}
147EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
148
149void 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}
160EXPORT_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}
265EXPORT_SYMBOL(nf_nat_mangle_udp_packet); 187EXPORT_SYMBOL(nf_nat_mangle_udp_packet);
266 188
267/* Adjust one found SACK option including checksum correction */
268static void
269sack_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 */
311static inline unsigned int
312nf_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 */
357int
358nf_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 */
413void nf_nat_follow_master(struct nf_conn *ct, 191void 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
25MODULE_LICENSE("GPL"); 26MODULE_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:
87void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, 87void 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
100int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr, 100int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr,