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

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>

authored by

Patrick McHardy and committed by
Pablo Neira Ayuso
41d73ec0 706f5151

+369 -376
+3 -6
include/linux/netfilter.h
··· 319 319 extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu; 320 320 321 321 struct nf_conn; 322 + enum ip_conntrack_info; 322 323 struct nlattr; 323 324 324 325 struct nfq_ct_hook { ··· 328 327 int (*parse)(const struct nlattr *attr, struct nf_conn *ct); 329 328 int (*attach_expect)(const struct nlattr *attr, struct nf_conn *ct, 330 329 u32 portid, u32 report); 330 + void (*seq_adjust)(struct sk_buff *skb, struct nf_conn *ct, 331 + enum ip_conntrack_info ctinfo, s32 off); 331 332 }; 332 333 extern struct nfq_ct_hook __rcu *nfq_ct_hook; 333 - 334 - struct nfq_ct_nat_hook { 335 - void (*seq_adjust)(struct sk_buff *skb, struct nf_conn *ct, 336 - u32 ctinfo, s32 off); 337 - }; 338 - extern struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook; 339 334 #else 340 335 static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} 341 336 #endif
+2
include/net/netfilter/nf_conntrack_extend.h
··· 9 9 NF_CT_EXT_HELPER, 10 10 #if defined(CONFIG_NF_NAT) || defined(CONFIG_NF_NAT_MODULE) 11 11 NF_CT_EXT_NAT, 12 + NF_CT_EXT_SEQADJ, 12 13 #endif 13 14 NF_CT_EXT_ACCT, 14 15 #ifdef CONFIG_NF_CONNTRACK_EVENTS ··· 32 31 33 32 #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help 34 33 #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat 34 + #define NF_CT_EXT_SEQADJ_TYPE struct nf_conn_seqadj 35 35 #define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter 36 36 #define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache 37 37 #define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
+49
include/net/netfilter/nf_conntrack_seqadj.h
··· 1 + #ifndef _NF_CONNTRACK_SEQADJ_H 2 + #define _NF_CONNTRACK_SEQADJ_H 3 + 4 + #include <net/netfilter/nf_conntrack_extend.h> 5 + 6 + /** 7 + * struct nf_ct_seqadj - sequence number adjustment information 8 + * 9 + * @correction_pos: position of the last TCP sequence number modification 10 + * @offset_before: sequence number offset before last modification 11 + * @offset_after: sequence number offset after last modification 12 + */ 13 + struct nf_ct_seqadj { 14 + u32 correction_pos; 15 + s32 offset_before; 16 + s32 offset_after; 17 + }; 18 + 19 + struct nf_conn_seqadj { 20 + struct nf_ct_seqadj seq[IP_CT_DIR_MAX]; 21 + }; 22 + 23 + static inline struct nf_conn_seqadj *nfct_seqadj(const struct nf_conn *ct) 24 + { 25 + return nf_ct_ext_find(ct, NF_CT_EXT_SEQADJ); 26 + } 27 + 28 + static inline struct nf_conn_seqadj *nfct_seqadj_ext_add(struct nf_conn *ct) 29 + { 30 + return nf_ct_ext_add(ct, NF_CT_EXT_SEQADJ, GFP_ATOMIC); 31 + } 32 + 33 + extern int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo, 34 + __be32 seq, s32 off); 35 + extern void nf_ct_tcp_seqadj_set(struct sk_buff *skb, 36 + struct nf_conn *ct, 37 + enum ip_conntrack_info ctinfo, 38 + s32 off); 39 + 40 + extern int nf_ct_seq_adjust(struct sk_buff *skb, 41 + struct nf_conn *ct, enum ip_conntrack_info ctinfo, 42 + unsigned int protoff); 43 + extern s32 nf_ct_seq_offset(const struct nf_conn *ct, enum ip_conntrack_dir, 44 + u32 seq); 45 + 46 + extern int nf_conntrack_seqadj_init(void); 47 + extern void nf_conntrack_seqadj_fini(void); 48 + 49 + #endif /* _NF_CONNTRACK_SEQADJ_H */
-10
include/net/netfilter/nf_nat.h
··· 13 13 #define HOOK2MANIP(hooknum) ((hooknum) != NF_INET_POST_ROUTING && \ 14 14 (hooknum) != NF_INET_LOCAL_IN) 15 15 16 - /* NAT sequence number modifications */ 17 - struct nf_nat_seq { 18 - /* position of the last TCP sequence number modification (if any) */ 19 - u_int32_t correction_pos; 20 - 21 - /* sequence number offset before and after last modification */ 22 - int32_t offset_before, offset_after; 23 - }; 24 - 25 16 #include <linux/list.h> 26 17 #include <linux/netfilter/nf_conntrack_pptp.h> 27 18 #include <net/netfilter/nf_conntrack_extend.h> ··· 30 39 /* The structure embedded in the conntrack structure. */ 31 40 struct nf_conn_nat { 32 41 struct hlist_node bysource; 33 - struct nf_nat_seq seq[IP_CT_DIR_MAX]; 34 42 struct nf_conn *ct; 35 43 union nf_conntrack_nat_help help; 36 44 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
-19
include/net/netfilter/nf_nat_helper.h
··· 39 39 const char *rep_buffer, 40 40 unsigned int rep_len); 41 41 42 - extern void nf_nat_set_seq_adjust(struct nf_conn *ct, 43 - enum ip_conntrack_info ctinfo, 44 - __be32 seq, s32 off); 45 - extern int nf_nat_seq_adjust(struct sk_buff *skb, 46 - struct nf_conn *ct, 47 - enum ip_conntrack_info ctinfo, 48 - unsigned int protoff); 49 - extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, 50 - struct nf_conn *ct, 51 - enum ip_conntrack_info ctinfo, 52 - unsigned int protoff); 53 - 54 42 /* Setup NAT on this expected conntrack so it follows master, but goes 55 43 * to port ct->master->saved_proto. */ 56 44 extern void nf_nat_follow_master(struct nf_conn *ct, 57 45 struct nf_conntrack_expect *this); 58 - 59 - extern s32 nf_nat_get_offset(const struct nf_conn *ct, 60 - enum ip_conntrack_dir dir, 61 - u32 seq); 62 - 63 - extern void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, 64 - u32 dir, s32 off); 65 46 66 47 #endif
+2 -1
include/uapi/linux/netfilter/nf_conntrack_common.h
··· 99 99 IPCT_PROTOINFO, /* protocol information has changed */ 100 100 IPCT_HELPER, /* new helper has been set */ 101 101 IPCT_MARK, /* new mark has been set */ 102 - IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */ 102 + IPCT_SEQADJ, /* sequence adjustment has changed */ 103 + IPCT_NATSEQADJ = IPCT_SEQADJ, 103 104 IPCT_SECMARK, /* new security mark has been set */ 104 105 IPCT_LABEL, /* new connlabel has been set */ 105 106 };
+2 -5
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
··· 25 25 #include <net/netfilter/nf_conntrack_l3proto.h> 26 26 #include <net/netfilter/nf_conntrack_zones.h> 27 27 #include <net/netfilter/nf_conntrack_core.h> 28 + #include <net/netfilter/nf_conntrack_seqadj.h> 28 29 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 29 30 #include <net/netfilter/nf_nat_helper.h> 30 31 #include <net/netfilter/ipv4/nf_defrag_ipv4.h> ··· 137 136 /* adjust seqs for loopback traffic only in outgoing direction */ 138 137 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 139 138 !nf_is_loopback_packet(skb)) { 140 - typeof(nf_nat_seq_adjust_hook) seq_adjust; 141 - 142 - seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); 143 - if (!seq_adjust || 144 - !seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) { 139 + if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) { 145 140 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 146 141 return NF_DROP; 147 142 }
+2 -5
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
··· 28 28 #include <net/netfilter/nf_conntrack_l3proto.h> 29 29 #include <net/netfilter/nf_conntrack_core.h> 30 30 #include <net/netfilter/nf_conntrack_zones.h> 31 + #include <net/netfilter/nf_conntrack_seqadj.h> 31 32 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 32 33 #include <net/netfilter/nf_nat_helper.h> 33 34 #include <net/netfilter/ipv6/nf_defrag_ipv6.h> ··· 159 158 /* adjust seqs for loopback traffic only in outgoing direction */ 160 159 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 161 160 !nf_is_loopback_packet(skb)) { 162 - typeof(nf_nat_seq_adjust_hook) seq_adjust; 163 - 164 - seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); 165 - if (!seq_adjust || 166 - !seq_adjust(skb, ct, ctinfo, protoff)) { 161 + if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) { 167 162 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 168 163 return NF_DROP; 169 164 }
+1 -1
net/netfilter/Makefile
··· 1 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 4 nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o 5 5 nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o 6 6 nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
+8 -8
net/netfilter/nf_conntrack_core.c
··· 39 39 #include <net/netfilter/nf_conntrack_l4proto.h> 40 40 #include <net/netfilter/nf_conntrack_expect.h> 41 41 #include <net/netfilter/nf_conntrack_helper.h> 42 + #include <net/netfilter/nf_conntrack_seqadj.h> 42 43 #include <net/netfilter/nf_conntrack_core.h> 43 44 #include <net/netfilter/nf_conntrack_extend.h> 44 45 #include <net/netfilter/nf_conntrack_acct.h> ··· 1327 1326 nf_ct_extend_unregister(&nf_ct_zone_extend); 1328 1327 #endif 1329 1328 nf_conntrack_proto_fini(); 1329 + nf_conntrack_seqadj_fini(); 1330 1330 nf_conntrack_labels_fini(); 1331 1331 nf_conntrack_helper_fini(); 1332 1332 nf_conntrack_timeout_fini(); ··· 1533 1531 if (ret < 0) 1534 1532 goto err_labels; 1535 1533 1534 + ret = nf_conntrack_seqadj_init(); 1535 + if (ret < 0) 1536 + goto err_seqadj; 1537 + 1536 1538 #ifdef CONFIG_NF_CONNTRACK_ZONES 1537 1539 ret = nf_ct_extend_register(&nf_ct_zone_extend); 1538 1540 if (ret < 0) ··· 1561 1555 nf_ct_extend_unregister(&nf_ct_zone_extend); 1562 1556 err_extend: 1563 1557 #endif 1558 + nf_conntrack_seqadj_fini(); 1559 + err_seqadj: 1564 1560 nf_conntrack_labels_fini(); 1565 1561 err_labels: 1566 1562 nf_conntrack_helper_fini(); ··· 1585 1577 /* For use by REJECT target */ 1586 1578 RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); 1587 1579 RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); 1588 - 1589 - /* Howto get NAT offsets */ 1590 - RCU_INIT_POINTER(nf_ct_nat_offset, NULL); 1591 1580 } 1592 1581 1593 1582 /* ··· 1671 1666 err_stat: 1672 1667 return ret; 1673 1668 } 1674 - 1675 - s32 (*nf_ct_nat_offset)(const struct nf_conn *ct, 1676 - enum ip_conntrack_dir dir, 1677 - u32 seq); 1678 - EXPORT_SYMBOL_GPL(nf_ct_nat_offset);
+54 -61
net/netfilter/nf_conntrack_netlink.c
··· 37 37 #include <net/netfilter/nf_conntrack_core.h> 38 38 #include <net/netfilter/nf_conntrack_expect.h> 39 39 #include <net/netfilter/nf_conntrack_helper.h> 40 + #include <net/netfilter/nf_conntrack_seqadj.h> 40 41 #include <net/netfilter/nf_conntrack_l3proto.h> 41 42 #include <net/netfilter/nf_conntrack_l4proto.h> 42 43 #include <net/netfilter/nf_conntrack_tuple.h> ··· 382 381 return -1; 383 382 } 384 383 385 - #ifdef CONFIG_NF_NAT_NEEDED 386 384 static int 387 - dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type) 385 + dump_ct_seq_adj(struct sk_buff *skb, const struct nf_ct_seqadj *seq, int type) 388 386 { 389 387 struct nlattr *nest_parms; 390 388 ··· 391 391 if (!nest_parms) 392 392 goto nla_put_failure; 393 393 394 - if (nla_put_be32(skb, CTA_NAT_SEQ_CORRECTION_POS, 395 - htonl(natseq->correction_pos)) || 396 - nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_BEFORE, 397 - htonl(natseq->offset_before)) || 398 - nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_AFTER, 399 - htonl(natseq->offset_after))) 394 + if (nla_put_be32(skb, CTA_SEQADJ_CORRECTION_POS, 395 + htonl(seq->correction_pos)) || 396 + nla_put_be32(skb, CTA_SEQADJ_OFFSET_BEFORE, 397 + htonl(seq->offset_before)) || 398 + nla_put_be32(skb, CTA_SEQADJ_OFFSET_AFTER, 399 + htonl(seq->offset_after))) 400 400 goto nla_put_failure; 401 401 402 402 nla_nest_end(skb, nest_parms); ··· 408 408 } 409 409 410 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; 414 - struct nf_conn_nat *nat = nfct_nat(ct); 413 + struct nf_conn_seqadj *seqadj = nfct_seqadj(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 417 return 0; 418 418 419 - natseq = &nat->seq[IP_CT_DIR_ORIGINAL]; 420 - if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_ORIG) == -1) 419 + seq = &seqadj->seq[IP_CT_DIR_ORIGINAL]; 420 + if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_ORIG) == -1) 421 421 return -1; 422 422 423 - natseq = &nat->seq[IP_CT_DIR_REPLY]; 424 - if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_REPLY) == -1) 423 + seq = &seqadj->seq[IP_CT_DIR_REPLY]; 424 + if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_REPLY) == -1) 425 425 return -1; 426 426 427 427 return 0; 428 428 } 429 - #else 430 - #define ctnetlink_dump_nat_seq_adj(a, b) (0) 431 - #endif 432 429 433 430 static inline int 434 431 ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) ··· 499 502 ctnetlink_dump_id(skb, ct) < 0 || 500 503 ctnetlink_dump_use(skb, ct) < 0 || 501 504 ctnetlink_dump_master(skb, ct) < 0 || 502 - ctnetlink_dump_nat_seq_adj(skb, ct) < 0) 505 + ctnetlink_dump_ct_seq_adj(skb, ct) < 0) 503 506 goto nla_put_failure; 504 507 505 508 nlmsg_end(skb, nlh); ··· 704 707 ctnetlink_dump_master(skb, ct) < 0) 705 708 goto nla_put_failure; 706 709 707 - if (events & (1 << IPCT_NATSEQADJ) && 708 - ctnetlink_dump_nat_seq_adj(skb, ct) < 0) 710 + if (events & (1 << IPCT_SEQADJ) && 711 + ctnetlink_dump_ct_seq_adj(skb, ct) < 0) 709 712 goto nla_put_failure; 710 713 } 711 714 ··· 1436 1439 return err; 1437 1440 } 1438 1441 1439 - #ifdef CONFIG_NF_NAT_NEEDED 1440 - static const struct nla_policy nat_seq_policy[CTA_NAT_SEQ_MAX+1] = { 1441 - [CTA_NAT_SEQ_CORRECTION_POS] = { .type = NLA_U32 }, 1442 - [CTA_NAT_SEQ_OFFSET_BEFORE] = { .type = NLA_U32 }, 1443 - [CTA_NAT_SEQ_OFFSET_AFTER] = { .type = NLA_U32 }, 1442 + static const struct nla_policy seqadj_policy[CTA_SEQADJ_MAX+1] = { 1443 + [CTA_SEQADJ_CORRECTION_POS] = { .type = NLA_U32 }, 1444 + [CTA_SEQADJ_OFFSET_BEFORE] = { .type = NLA_U32 }, 1445 + [CTA_SEQADJ_OFFSET_AFTER] = { .type = NLA_U32 }, 1444 1446 }; 1445 1447 1446 1448 static inline int 1447 - change_nat_seq_adj(struct nf_nat_seq *natseq, const struct nlattr * const attr) 1449 + change_seq_adj(struct nf_ct_seqadj *seq, const struct nlattr * const attr) 1448 1450 { 1449 1451 int err; 1450 - struct nlattr *cda[CTA_NAT_SEQ_MAX+1]; 1452 + struct nlattr *cda[CTA_SEQADJ_MAX+1]; 1451 1453 1452 - err = nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, nat_seq_policy); 1454 + err = nla_parse_nested(cda, CTA_SEQADJ_MAX, attr, seqadj_policy); 1453 1455 if (err < 0) 1454 1456 return err; 1455 1457 1456 - if (!cda[CTA_NAT_SEQ_CORRECTION_POS]) 1458 + if (!cda[CTA_SEQADJ_CORRECTION_POS]) 1457 1459 return -EINVAL; 1458 1460 1459 - natseq->correction_pos = 1460 - ntohl(nla_get_be32(cda[CTA_NAT_SEQ_CORRECTION_POS])); 1461 + seq->correction_pos = 1462 + ntohl(nla_get_be32(cda[CTA_SEQADJ_CORRECTION_POS])); 1461 1463 1462 - if (!cda[CTA_NAT_SEQ_OFFSET_BEFORE]) 1464 + if (!cda[CTA_SEQADJ_OFFSET_BEFORE]) 1463 1465 return -EINVAL; 1464 1466 1465 - natseq->offset_before = 1466 - ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_BEFORE])); 1467 + seq->offset_before = 1468 + ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_BEFORE])); 1467 1469 1468 - if (!cda[CTA_NAT_SEQ_OFFSET_AFTER]) 1470 + if (!cda[CTA_SEQADJ_OFFSET_AFTER]) 1469 1471 return -EINVAL; 1470 1472 1471 - natseq->offset_after = 1472 - ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_AFTER])); 1473 + seq->offset_after = 1474 + ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_AFTER])); 1473 1475 1474 1476 return 0; 1475 1477 } 1476 1478 1477 1479 static int 1478 - ctnetlink_change_nat_seq_adj(struct nf_conn *ct, 1479 - const struct nlattr * const cda[]) 1480 + ctnetlink_change_seq_adj(struct nf_conn *ct, 1481 + const struct nlattr * const cda[]) 1480 1482 { 1483 + struct nf_conn_seqadj *seqadj = nfct_seqadj(ct); 1481 1484 int ret = 0; 1482 - struct nf_conn_nat *nat = nfct_nat(ct); 1483 1485 1484 - if (!nat) 1486 + if (!seqadj) 1485 1487 return 0; 1486 1488 1487 - if (cda[CTA_NAT_SEQ_ADJ_ORIG]) { 1488 - ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_ORIGINAL], 1489 - cda[CTA_NAT_SEQ_ADJ_ORIG]); 1489 + if (cda[CTA_SEQ_ADJ_ORIG]) { 1490 + ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_ORIGINAL], 1491 + cda[CTA_SEQ_ADJ_ORIG]); 1490 1492 if (ret < 0) 1491 1493 return ret; 1492 1494 1493 1495 ct->status |= IPS_SEQ_ADJUST; 1494 1496 } 1495 1497 1496 - if (cda[CTA_NAT_SEQ_ADJ_REPLY]) { 1497 - ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_REPLY], 1498 - cda[CTA_NAT_SEQ_ADJ_REPLY]); 1498 + if (cda[CTA_SEQ_ADJ_REPLY]) { 1499 + ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_REPLY], 1500 + cda[CTA_SEQ_ADJ_REPLY]); 1499 1501 if (ret < 0) 1500 1502 return ret; 1501 1503 ··· 1503 1507 1504 1508 return 0; 1505 1509 } 1506 - #endif 1507 1510 1508 1511 static int 1509 1512 ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) ··· 1568 1573 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); 1569 1574 #endif 1570 1575 1571 - #ifdef CONFIG_NF_NAT_NEEDED 1572 - if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { 1573 - err = ctnetlink_change_nat_seq_adj(ct, cda); 1576 + if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) { 1577 + err = ctnetlink_change_seq_adj(ct, cda); 1574 1578 if (err < 0) 1575 1579 return err; 1576 1580 } 1577 - #endif 1581 + 1578 1582 if (cda[CTA_LABELS]) { 1579 1583 err = ctnetlink_attach_labels(ct, cda); 1580 1584 if (err < 0) ··· 1678 1684 goto err2; 1679 1685 } 1680 1686 1681 - #ifdef CONFIG_NF_NAT_NEEDED 1682 - if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { 1683 - err = ctnetlink_change_nat_seq_adj(ct, cda); 1687 + if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) { 1688 + err = ctnetlink_change_seq_adj(ct, cda); 1684 1689 if (err < 0) 1685 1690 goto err2; 1686 1691 } 1687 - #endif 1688 1692 1689 1693 memset(&ct->proto, 0, sizeof(ct->proto)); 1690 1694 if (cda[CTA_PROTOINFO]) { ··· 1796 1804 (1 << IPCT_ASSURED) | 1797 1805 (1 << IPCT_HELPER) | 1798 1806 (1 << IPCT_PROTOINFO) | 1799 - (1 << IPCT_NATSEQADJ) | 1807 + (1 << IPCT_SEQADJ) | 1800 1808 (1 << IPCT_MARK) | events, 1801 1809 ct, NETLINK_CB(skb).portid, 1802 1810 nlmsg_report(nlh)); ··· 1819 1827 (1 << IPCT_HELPER) | 1820 1828 (1 << IPCT_LABEL) | 1821 1829 (1 << IPCT_PROTOINFO) | 1822 - (1 << IPCT_NATSEQADJ) | 1830 + (1 << IPCT_SEQADJ) | 1823 1831 (1 << IPCT_MARK), 1824 1832 ct, NETLINK_CB(skb).portid, 1825 1833 nlmsg_report(nlh)); ··· 2074 2082 goto nla_put_failure; 2075 2083 2076 2084 if ((ct->status & IPS_SEQ_ADJUST) && 2077 - ctnetlink_dump_nat_seq_adj(skb, ct) < 0) 2085 + ctnetlink_dump_ct_seq_adj(skb, ct) < 0) 2078 2086 goto nla_put_failure; 2079 2087 2080 2088 #ifdef CONFIG_NF_CONNTRACK_MARK ··· 2203 2211 .build = ctnetlink_nfqueue_build, 2204 2212 .parse = ctnetlink_nfqueue_parse, 2205 2213 .attach_expect = ctnetlink_nfqueue_attach_expect, 2214 + .seq_adjust = nf_ct_tcp_seqadj_set, 2206 2215 }; 2207 2216 #endif /* CONFIG_NETFILTER_NETLINK_QUEUE_CT */ 2208 2217
+2 -16
net/netfilter/nf_conntrack_proto_tcp.c
··· 27 27 #include <net/netfilter/nf_conntrack.h> 28 28 #include <net/netfilter/nf_conntrack_l4proto.h> 29 29 #include <net/netfilter/nf_conntrack_ecache.h> 30 + #include <net/netfilter/nf_conntrack_seqadj.h> 30 31 #include <net/netfilter/nf_log.h> 31 32 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 32 33 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> ··· 496 495 } 497 496 } 498 497 499 - #ifdef CONFIG_NF_NAT_NEEDED 500 - static inline s32 nat_offset(const struct nf_conn *ct, 501 - enum ip_conntrack_dir dir, 502 - u32 seq) 503 - { 504 - typeof(nf_ct_nat_offset) get_offset = rcu_dereference(nf_ct_nat_offset); 505 - 506 - return get_offset != NULL ? get_offset(ct, dir, seq) : 0; 507 - } 508 - #define NAT_OFFSET(ct, dir, seq) \ 509 - (nat_offset(ct, dir, seq)) 510 - #else 511 - #define NAT_OFFSET(ct, dir, seq) 0 512 - #endif 513 - 514 498 static bool tcp_in_window(const struct nf_conn *ct, 515 499 struct ip_ct_tcp *state, 516 500 enum ip_conntrack_dir dir, ··· 526 540 tcp_sack(skb, dataoff, tcph, &sack); 527 541 528 542 /* Take into account NAT sequence number mangling */ 529 - receiver_offset = NAT_OFFSET(ct, !dir, ack - 1); 543 + receiver_offset = nf_ct_seq_offset(ct, !dir, ack - 1); 530 544 ack -= receiver_offset; 531 545 sack -= receiver_offset; 532 546
+218
net/netfilter/nf_conntrack_seqadj.c
··· 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 + }
+4 -12
net/netfilter/nf_nat_core.c
··· 25 25 #include <net/netfilter/nf_nat_core.h> 26 26 #include <net/netfilter/nf_nat_helper.h> 27 27 #include <net/netfilter/nf_conntrack_helper.h> 28 + #include <net/netfilter/nf_conntrack_seqadj.h> 28 29 #include <net/netfilter/nf_conntrack_l3proto.h> 29 30 #include <net/netfilter/nf_conntrack_zones.h> 30 31 #include <linux/netfilter/nf_nat.h> ··· 403 402 ct->status |= IPS_SRC_NAT; 404 403 else 405 404 ct->status |= IPS_DST_NAT; 405 + 406 + if (nfct_help(ct)) 407 + nfct_seqadj_ext_add(ct); 406 408 } 407 409 408 410 if (maniptype == NF_NAT_MANIP_SRC) { ··· 768 764 .expectfn = nf_nat_follow_master, 769 765 }; 770 766 771 - static struct nfq_ct_nat_hook nfq_ct_nat = { 772 - .seq_adjust = nf_nat_tcp_seq_adjust, 773 - }; 774 - 775 767 static int __init nf_nat_init(void) 776 768 { 777 769 int ret; ··· 787 787 /* Initialize fake conntrack so that NAT will skip it */ 788 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 790 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); 793 791 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, 794 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 793 #ifdef CONFIG_XFRM 799 794 BUG_ON(nf_nat_decode_session_hook != NULL); 800 795 RCU_INIT_POINTER(nf_nat_decode_session_hook, __nf_nat_decode_session); ··· 808 813 unregister_pernet_subsys(&nf_nat_net_ops); 809 814 nf_ct_extend_unregister(&nat_extend); 810 815 nf_ct_helper_expectfn_unregister(&follow_master_nat); 811 - RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); 812 816 RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); 813 - RCU_INIT_POINTER(nf_ct_nat_offset, NULL); 814 - RCU_INIT_POINTER(nfq_ct_nat_hook, NULL); 815 817 #ifdef CONFIG_XFRM 816 818 RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); 817 819 #endif
+3 -225
net/netfilter/nf_nat_helper.c
··· 20 20 #include <net/netfilter/nf_conntrack_helper.h> 21 21 #include <net/netfilter/nf_conntrack_ecache.h> 22 22 #include <net/netfilter/nf_conntrack_expect.h> 23 + #include <net/netfilter/nf_conntrack_seqadj.h> 23 24 #include <net/netfilter/nf_nat.h> 24 25 #include <net/netfilter/nf_nat_l3proto.h> 25 26 #include <net/netfilter/nf_nat_l4proto.h> 26 27 #include <net/netfilter/nf_nat_core.h> 27 28 #include <net/netfilter/nf_nat_helper.h> 28 - 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 29 84 30 /* Frobs data inside this packet, which is linear. */ 85 31 static void mangle_contents(struct sk_buff *skb, ··· 81 135 return 1; 82 136 } 83 137 84 - void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo, 85 - __be32 seq, s32 off) 86 - { 87 - if (!off) 88 - return; 89 - set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); 90 - adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo); 91 - nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); 92 - } 93 - EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust); 94 - 95 - void nf_nat_tcp_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, 96 - u32 ctinfo, int off) 97 - { 98 - const struct tcphdr *th; 99 - 100 - if (nf_ct_protonum(ct) != IPPROTO_TCP) 101 - return; 102 - 103 - th = (struct tcphdr *)(skb_network_header(skb)+ ip_hdrlen(skb)); 104 - nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); 105 - } 106 - EXPORT_SYMBOL_GPL(nf_nat_tcp_seq_adjust); 107 - 108 138 /* Generic function for mangling variable-length address changes inside 109 139 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX 110 140 * command in FTP). ··· 125 203 datalen, oldlen); 126 204 127 205 if (adjust && rep_len != match_len) 128 - nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq, 129 - (int)rep_len - (int)match_len); 206 + nf_ct_seqadj_set(ct, ctinfo, tcph->seq, 207 + (int)rep_len - (int)match_len); 130 208 131 209 return 1; 132 210 } ··· 185 263 return 1; 186 264 } 187 265 EXPORT_SYMBOL(nf_nat_mangle_udp_packet); 188 - 189 - /* Adjust one found SACK option including checksum correction */ 190 - static void 191 - sack_adjust(struct sk_buff *skb, 192 - struct tcphdr *tcph, 193 - unsigned int sackoff, 194 - unsigned int sackend, 195 - struct nf_nat_seq *natseq) 196 - { 197 - while (sackoff < sackend) { 198 - struct tcp_sack_block_wire *sack; 199 - __be32 new_start_seq, new_end_seq; 200 - 201 - sack = (void *)skb->data + sackoff; 202 - if (after(ntohl(sack->start_seq) - natseq->offset_before, 203 - natseq->correction_pos)) 204 - new_start_seq = htonl(ntohl(sack->start_seq) 205 - - natseq->offset_after); 206 - else 207 - new_start_seq = htonl(ntohl(sack->start_seq) 208 - - natseq->offset_before); 209 - 210 - if (after(ntohl(sack->end_seq) - natseq->offset_before, 211 - natseq->correction_pos)) 212 - new_end_seq = htonl(ntohl(sack->end_seq) 213 - - natseq->offset_after); 214 - else 215 - new_end_seq = htonl(ntohl(sack->end_seq) 216 - - natseq->offset_before); 217 - 218 - pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", 219 - ntohl(sack->start_seq), new_start_seq, 220 - ntohl(sack->end_seq), new_end_seq); 221 - 222 - inet_proto_csum_replace4(&tcph->check, skb, 223 - sack->start_seq, new_start_seq, 0); 224 - inet_proto_csum_replace4(&tcph->check, skb, 225 - sack->end_seq, new_end_seq, 0); 226 - sack->start_seq = new_start_seq; 227 - sack->end_seq = new_end_seq; 228 - sackoff += sizeof(*sack); 229 - } 230 - } 231 - 232 - /* TCP SACK sequence number adjustment */ 233 - static inline unsigned int 234 - nf_nat_sack_adjust(struct sk_buff *skb, 235 - unsigned int protoff, 236 - struct tcphdr *tcph, 237 - struct nf_conn *ct, 238 - enum ip_conntrack_info ctinfo) 239 - { 240 - unsigned int dir, optoff, optend; 241 - struct nf_conn_nat *nat = nfct_nat(ct); 242 - 243 - optoff = protoff + sizeof(struct tcphdr); 244 - optend = protoff + tcph->doff * 4; 245 - 246 - if (!skb_make_writable(skb, optend)) 247 - return 0; 248 - 249 - dir = CTINFO2DIR(ctinfo); 250 - 251 - while (optoff < optend) { 252 - /* Usually: option, length. */ 253 - unsigned char *op = skb->data + optoff; 254 - 255 - switch (op[0]) { 256 - case TCPOPT_EOL: 257 - return 1; 258 - case TCPOPT_NOP: 259 - optoff++; 260 - continue; 261 - default: 262 - /* no partial options */ 263 - if (optoff + 1 == optend || 264 - optoff + op[1] > optend || 265 - op[1] < 2) 266 - return 0; 267 - if (op[0] == TCPOPT_SACK && 268 - op[1] >= 2+TCPOLEN_SACK_PERBLOCK && 269 - ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) 270 - sack_adjust(skb, tcph, optoff+2, 271 - optoff+op[1], &nat->seq[!dir]); 272 - optoff += op[1]; 273 - } 274 - } 275 - return 1; 276 - } 277 - 278 - /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ 279 - int 280 - nf_nat_seq_adjust(struct sk_buff *skb, 281 - struct nf_conn *ct, 282 - enum ip_conntrack_info ctinfo, 283 - unsigned int protoff) 284 - { 285 - struct tcphdr *tcph; 286 - int dir; 287 - __be32 newseq, newack; 288 - s32 seqoff, ackoff; 289 - struct nf_conn_nat *nat = nfct_nat(ct); 290 - struct nf_nat_seq *this_way, *other_way; 291 - int res; 292 - 293 - dir = CTINFO2DIR(ctinfo); 294 - 295 - this_way = &nat->seq[dir]; 296 - other_way = &nat->seq[!dir]; 297 - 298 - if (!skb_make_writable(skb, protoff + sizeof(*tcph))) 299 - return 0; 300 - 301 - tcph = (void *)skb->data + protoff; 302 - spin_lock_bh(&ct->lock); 303 - if (after(ntohl(tcph->seq), this_way->correction_pos)) 304 - seqoff = this_way->offset_after; 305 - else 306 - seqoff = this_way->offset_before; 307 - 308 - if (after(ntohl(tcph->ack_seq) - other_way->offset_before, 309 - other_way->correction_pos)) 310 - ackoff = other_way->offset_after; 311 - else 312 - ackoff = other_way->offset_before; 313 - 314 - newseq = htonl(ntohl(tcph->seq) + seqoff); 315 - newack = htonl(ntohl(tcph->ack_seq) - ackoff); 316 - 317 - inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0); 318 - inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0); 319 - 320 - pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n", 321 - ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), 322 - ntohl(newack)); 323 - 324 - tcph->seq = newseq; 325 - tcph->ack_seq = newack; 326 - 327 - res = nf_nat_sack_adjust(skb, protoff, tcph, ct, ctinfo); 328 - spin_unlock_bh(&ct->lock); 329 - 330 - return res; 331 - } 332 266 333 267 /* Setup NAT on this expected conntrack so it follows master. */ 334 268 /* If we fail to get a free NAT slot, we'll get dropped on confirm */
+2 -1
net/netfilter/nf_nat_sip.c
··· 20 20 #include <net/netfilter/nf_nat_helper.h> 21 21 #include <net/netfilter/nf_conntrack_helper.h> 22 22 #include <net/netfilter/nf_conntrack_expect.h> 23 + #include <net/netfilter/nf_conntrack_seqadj.h> 23 24 #include <linux/netfilter/nf_conntrack_sip.h> 24 25 25 26 MODULE_LICENSE("GPL"); ··· 309 308 return; 310 309 311 310 th = (struct tcphdr *)(skb->data + protoff); 312 - nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); 311 + nf_ct_seqadj_set(ct, ctinfo, th->seq, off); 313 312 } 314 313 315 314 /* Handles expected signalling connections and media streams */