Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

+2381 -495
+1 -1
drivers/net/wan/hdlc_cisco.c
··· 72 72 } 73 73 skb_reserve(skb, 4); 74 74 cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); 75 - data = (cisco_packet*)skb->data; 75 + data = (cisco_packet*)(skb->data + 4); 76 76 77 77 data->type = htonl(type); 78 78 data->par1 = htonl(par1);
+4 -4
include/linux/if_vlan.h
··· 42 42 struct vlan_ethhdr { 43 43 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ 44 44 unsigned char h_source[ETH_ALEN]; /* source ether addr */ 45 - unsigned short h_vlan_proto; /* Should always be 0x8100 */ 46 - unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ 45 + __be16 h_vlan_proto; /* Should always be 0x8100 */ 46 + __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */ 47 47 unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ 48 48 }; 49 49 ··· 55 55 } 56 56 57 57 struct vlan_hdr { 58 - unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ 59 - unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ 58 + __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */ 59 + __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */ 60 60 }; 61 61 62 62 #define VLAN_VID_MASK 0xfff
+13 -1
include/linux/netfilter_ipv4/ip_conntrack.h
··· 133 133 134 134 #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> 135 135 #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> 136 + #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> 136 137 #include <linux/netfilter_ipv4/ip_conntrack_sctp.h> 137 138 138 139 /* per conntrack: protocol private data */ 139 140 union ip_conntrack_proto { 140 141 /* insert conntrack proto private data here */ 142 + struct ip_ct_gre gre; 141 143 struct ip_ct_sctp sctp; 142 144 struct ip_ct_tcp tcp; 143 145 struct ip_ct_icmp icmp; ··· 150 148 }; 151 149 152 150 /* Add protocol helper include file here */ 151 + #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> 153 152 #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> 154 153 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> 155 154 #include <linux/netfilter_ipv4/ip_conntrack_irc.h> ··· 158 155 /* per conntrack: application helper private data */ 159 156 union ip_conntrack_help { 160 157 /* insert conntrack helper private data (master) here */ 158 + struct ip_ct_pptp_master ct_pptp_info; 161 159 struct ip_ct_ftp_master ct_ftp_info; 162 160 struct ip_ct_irc_master ct_irc_info; 163 161 }; 164 162 165 163 #ifdef CONFIG_IP_NF_NAT_NEEDED 166 164 #include <linux/netfilter_ipv4/ip_nat.h> 165 + #include <linux/netfilter_ipv4/ip_nat_pptp.h> 166 + 167 + /* per conntrack: nat application helper private data */ 168 + union ip_conntrack_nat_help { 169 + /* insert nat helper private data here */ 170 + struct ip_nat_pptp nat_pptp_info; 171 + }; 167 172 #endif 168 173 169 174 #include <linux/types.h> ··· 234 223 #ifdef CONFIG_IP_NF_NAT_NEEDED 235 224 struct { 236 225 struct ip_nat_info info; 226 + union ip_conntrack_nat_help help; 237 227 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ 238 228 defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) 239 229 int masq_index; ··· 384 372 __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); 385 373 386 374 extern struct ip_conntrack_expect * 387 - ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); 375 + ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); 388 376 389 377 extern struct ip_conntrack_tuple_hash * 390 378 __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
+332
include/linux/netfilter_ipv4/ip_conntrack_pptp.h
··· 1 + /* PPTP constants and structs */ 2 + #ifndef _CONNTRACK_PPTP_H 3 + #define _CONNTRACK_PPTP_H 4 + 5 + /* state of the control session */ 6 + enum pptp_ctrlsess_state { 7 + PPTP_SESSION_NONE, /* no session present */ 8 + PPTP_SESSION_ERROR, /* some session error */ 9 + PPTP_SESSION_STOPREQ, /* stop_sess request seen */ 10 + PPTP_SESSION_REQUESTED, /* start_sess request seen */ 11 + PPTP_SESSION_CONFIRMED, /* session established */ 12 + }; 13 + 14 + /* state of the call inside the control session */ 15 + enum pptp_ctrlcall_state { 16 + PPTP_CALL_NONE, 17 + PPTP_CALL_ERROR, 18 + PPTP_CALL_OUT_REQ, 19 + PPTP_CALL_OUT_CONF, 20 + PPTP_CALL_IN_REQ, 21 + PPTP_CALL_IN_REP, 22 + PPTP_CALL_IN_CONF, 23 + PPTP_CALL_CLEAR_REQ, 24 + }; 25 + 26 + 27 + /* conntrack private data */ 28 + struct ip_ct_pptp_master { 29 + enum pptp_ctrlsess_state sstate; /* session state */ 30 + 31 + /* everything below is going to be per-expectation in newnat, 32 + * since there could be more than one call within one session */ 33 + enum pptp_ctrlcall_state cstate; /* call state */ 34 + u_int16_t pac_call_id; /* call id of PAC, host byte order */ 35 + u_int16_t pns_call_id; /* call id of PNS, host byte order */ 36 + 37 + /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack 38 + * and therefore imposes a fixed limit on the number of maps */ 39 + struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; 40 + }; 41 + 42 + /* conntrack_expect private member */ 43 + struct ip_ct_pptp_expect { 44 + enum pptp_ctrlcall_state cstate; /* call state */ 45 + u_int16_t pac_call_id; /* call id of PAC */ 46 + u_int16_t pns_call_id; /* call id of PNS */ 47 + }; 48 + 49 + 50 + #ifdef __KERNEL__ 51 + 52 + #define IP_CONNTR_PPTP PPTP_CONTROL_PORT 53 + 54 + #define PPTP_CONTROL_PORT 1723 55 + 56 + #define PPTP_PACKET_CONTROL 1 57 + #define PPTP_PACKET_MGMT 2 58 + 59 + #define PPTP_MAGIC_COOKIE 0x1a2b3c4d 60 + 61 + struct pptp_pkt_hdr { 62 + __u16 packetLength; 63 + __u16 packetType; 64 + __u32 magicCookie; 65 + }; 66 + 67 + /* PptpControlMessageType values */ 68 + #define PPTP_START_SESSION_REQUEST 1 69 + #define PPTP_START_SESSION_REPLY 2 70 + #define PPTP_STOP_SESSION_REQUEST 3 71 + #define PPTP_STOP_SESSION_REPLY 4 72 + #define PPTP_ECHO_REQUEST 5 73 + #define PPTP_ECHO_REPLY 6 74 + #define PPTP_OUT_CALL_REQUEST 7 75 + #define PPTP_OUT_CALL_REPLY 8 76 + #define PPTP_IN_CALL_REQUEST 9 77 + #define PPTP_IN_CALL_REPLY 10 78 + #define PPTP_IN_CALL_CONNECT 11 79 + #define PPTP_CALL_CLEAR_REQUEST 12 80 + #define PPTP_CALL_DISCONNECT_NOTIFY 13 81 + #define PPTP_WAN_ERROR_NOTIFY 14 82 + #define PPTP_SET_LINK_INFO 15 83 + 84 + #define PPTP_MSG_MAX 15 85 + 86 + /* PptpGeneralError values */ 87 + #define PPTP_ERROR_CODE_NONE 0 88 + #define PPTP_NOT_CONNECTED 1 89 + #define PPTP_BAD_FORMAT 2 90 + #define PPTP_BAD_VALUE 3 91 + #define PPTP_NO_RESOURCE 4 92 + #define PPTP_BAD_CALLID 5 93 + #define PPTP_REMOVE_DEVICE_ERROR 6 94 + 95 + struct PptpControlHeader { 96 + __u16 messageType; 97 + __u16 reserved; 98 + }; 99 + 100 + /* FramingCapability Bitmap Values */ 101 + #define PPTP_FRAME_CAP_ASYNC 0x1 102 + #define PPTP_FRAME_CAP_SYNC 0x2 103 + 104 + /* BearerCapability Bitmap Values */ 105 + #define PPTP_BEARER_CAP_ANALOG 0x1 106 + #define PPTP_BEARER_CAP_DIGITAL 0x2 107 + 108 + struct PptpStartSessionRequest { 109 + __u16 protocolVersion; 110 + __u8 reserved1; 111 + __u8 reserved2; 112 + __u32 framingCapability; 113 + __u32 bearerCapability; 114 + __u16 maxChannels; 115 + __u16 firmwareRevision; 116 + __u8 hostName[64]; 117 + __u8 vendorString[64]; 118 + }; 119 + 120 + /* PptpStartSessionResultCode Values */ 121 + #define PPTP_START_OK 1 122 + #define PPTP_START_GENERAL_ERROR 2 123 + #define PPTP_START_ALREADY_CONNECTED 3 124 + #define PPTP_START_NOT_AUTHORIZED 4 125 + #define PPTP_START_UNKNOWN_PROTOCOL 5 126 + 127 + struct PptpStartSessionReply { 128 + __u16 protocolVersion; 129 + __u8 resultCode; 130 + __u8 generalErrorCode; 131 + __u32 framingCapability; 132 + __u32 bearerCapability; 133 + __u16 maxChannels; 134 + __u16 firmwareRevision; 135 + __u8 hostName[64]; 136 + __u8 vendorString[64]; 137 + }; 138 + 139 + /* PptpStopReasons */ 140 + #define PPTP_STOP_NONE 1 141 + #define PPTP_STOP_PROTOCOL 2 142 + #define PPTP_STOP_LOCAL_SHUTDOWN 3 143 + 144 + struct PptpStopSessionRequest { 145 + __u8 reason; 146 + }; 147 + 148 + /* PptpStopSessionResultCode */ 149 + #define PPTP_STOP_OK 1 150 + #define PPTP_STOP_GENERAL_ERROR 2 151 + 152 + struct PptpStopSessionReply { 153 + __u8 resultCode; 154 + __u8 generalErrorCode; 155 + }; 156 + 157 + struct PptpEchoRequest { 158 + __u32 identNumber; 159 + }; 160 + 161 + /* PptpEchoReplyResultCode */ 162 + #define PPTP_ECHO_OK 1 163 + #define PPTP_ECHO_GENERAL_ERROR 2 164 + 165 + struct PptpEchoReply { 166 + __u32 identNumber; 167 + __u8 resultCode; 168 + __u8 generalErrorCode; 169 + __u16 reserved; 170 + }; 171 + 172 + /* PptpFramingType */ 173 + #define PPTP_ASYNC_FRAMING 1 174 + #define PPTP_SYNC_FRAMING 2 175 + #define PPTP_DONT_CARE_FRAMING 3 176 + 177 + /* PptpCallBearerType */ 178 + #define PPTP_ANALOG_TYPE 1 179 + #define PPTP_DIGITAL_TYPE 2 180 + #define PPTP_DONT_CARE_BEARER_TYPE 3 181 + 182 + struct PptpOutCallRequest { 183 + __u16 callID; 184 + __u16 callSerialNumber; 185 + __u32 minBPS; 186 + __u32 maxBPS; 187 + __u32 bearerType; 188 + __u32 framingType; 189 + __u16 packetWindow; 190 + __u16 packetProcDelay; 191 + __u16 reserved1; 192 + __u16 phoneNumberLength; 193 + __u16 reserved2; 194 + __u8 phoneNumber[64]; 195 + __u8 subAddress[64]; 196 + }; 197 + 198 + /* PptpCallResultCode */ 199 + #define PPTP_OUTCALL_CONNECT 1 200 + #define PPTP_OUTCALL_GENERAL_ERROR 2 201 + #define PPTP_OUTCALL_NO_CARRIER 3 202 + #define PPTP_OUTCALL_BUSY 4 203 + #define PPTP_OUTCALL_NO_DIAL_TONE 5 204 + #define PPTP_OUTCALL_TIMEOUT 6 205 + #define PPTP_OUTCALL_DONT_ACCEPT 7 206 + 207 + struct PptpOutCallReply { 208 + __u16 callID; 209 + __u16 peersCallID; 210 + __u8 resultCode; 211 + __u8 generalErrorCode; 212 + __u16 causeCode; 213 + __u32 connectSpeed; 214 + __u16 packetWindow; 215 + __u16 packetProcDelay; 216 + __u32 physChannelID; 217 + }; 218 + 219 + struct PptpInCallRequest { 220 + __u16 callID; 221 + __u16 callSerialNumber; 222 + __u32 callBearerType; 223 + __u32 physChannelID; 224 + __u16 dialedNumberLength; 225 + __u16 dialingNumberLength; 226 + __u8 dialedNumber[64]; 227 + __u8 dialingNumber[64]; 228 + __u8 subAddress[64]; 229 + }; 230 + 231 + /* PptpInCallResultCode */ 232 + #define PPTP_INCALL_ACCEPT 1 233 + #define PPTP_INCALL_GENERAL_ERROR 2 234 + #define PPTP_INCALL_DONT_ACCEPT 3 235 + 236 + struct PptpInCallReply { 237 + __u16 callID; 238 + __u16 peersCallID; 239 + __u8 resultCode; 240 + __u8 generalErrorCode; 241 + __u16 packetWindow; 242 + __u16 packetProcDelay; 243 + __u16 reserved; 244 + }; 245 + 246 + struct PptpInCallConnected { 247 + __u16 peersCallID; 248 + __u16 reserved; 249 + __u32 connectSpeed; 250 + __u16 packetWindow; 251 + __u16 packetProcDelay; 252 + __u32 callFramingType; 253 + }; 254 + 255 + struct PptpClearCallRequest { 256 + __u16 callID; 257 + __u16 reserved; 258 + }; 259 + 260 + struct PptpCallDisconnectNotify { 261 + __u16 callID; 262 + __u8 resultCode; 263 + __u8 generalErrorCode; 264 + __u16 causeCode; 265 + __u16 reserved; 266 + __u8 callStatistics[128]; 267 + }; 268 + 269 + struct PptpWanErrorNotify { 270 + __u16 peersCallID; 271 + __u16 reserved; 272 + __u32 crcErrors; 273 + __u32 framingErrors; 274 + __u32 hardwareOverRuns; 275 + __u32 bufferOverRuns; 276 + __u32 timeoutErrors; 277 + __u32 alignmentErrors; 278 + }; 279 + 280 + struct PptpSetLinkInfo { 281 + __u16 peersCallID; 282 + __u16 reserved; 283 + __u32 sendAccm; 284 + __u32 recvAccm; 285 + }; 286 + 287 + 288 + struct pptp_priv_data { 289 + __u16 call_id; 290 + __u16 mcall_id; 291 + __u16 pcall_id; 292 + }; 293 + 294 + union pptp_ctrl_union { 295 + struct PptpStartSessionRequest sreq; 296 + struct PptpStartSessionReply srep; 297 + struct PptpStopSessionRequest streq; 298 + struct PptpStopSessionReply strep; 299 + struct PptpOutCallRequest ocreq; 300 + struct PptpOutCallReply ocack; 301 + struct PptpInCallRequest icreq; 302 + struct PptpInCallReply icack; 303 + struct PptpInCallConnected iccon; 304 + struct PptpClearCallRequest clrreq; 305 + struct PptpCallDisconnectNotify disc; 306 + struct PptpWanErrorNotify wanerr; 307 + struct PptpSetLinkInfo setlink; 308 + }; 309 + 310 + extern int 311 + (*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, 312 + struct ip_conntrack *ct, 313 + enum ip_conntrack_info ctinfo, 314 + struct PptpControlHeader *ctlh, 315 + union pptp_ctrl_union *pptpReq); 316 + 317 + extern int 318 + (*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, 319 + struct ip_conntrack *ct, 320 + enum ip_conntrack_info ctinfo, 321 + struct PptpControlHeader *ctlh, 322 + union pptp_ctrl_union *pptpReq); 323 + 324 + extern int 325 + (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig, 326 + struct ip_conntrack_expect *exp_reply); 327 + 328 + extern void 329 + (*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, 330 + struct ip_conntrack_expect *exp); 331 + #endif /* __KERNEL__ */ 332 + #endif /* _CONNTRACK_PPTP_H */
+114
include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
··· 1 + #ifndef _CONNTRACK_PROTO_GRE_H 2 + #define _CONNTRACK_PROTO_GRE_H 3 + #include <asm/byteorder.h> 4 + 5 + /* GRE PROTOCOL HEADER */ 6 + 7 + /* GRE Version field */ 8 + #define GRE_VERSION_1701 0x0 9 + #define GRE_VERSION_PPTP 0x1 10 + 11 + /* GRE Protocol field */ 12 + #define GRE_PROTOCOL_PPTP 0x880B 13 + 14 + /* GRE Flags */ 15 + #define GRE_FLAG_C 0x80 16 + #define GRE_FLAG_R 0x40 17 + #define GRE_FLAG_K 0x20 18 + #define GRE_FLAG_S 0x10 19 + #define GRE_FLAG_A 0x80 20 + 21 + #define GRE_IS_C(f) ((f)&GRE_FLAG_C) 22 + #define GRE_IS_R(f) ((f)&GRE_FLAG_R) 23 + #define GRE_IS_K(f) ((f)&GRE_FLAG_K) 24 + #define GRE_IS_S(f) ((f)&GRE_FLAG_S) 25 + #define GRE_IS_A(f) ((f)&GRE_FLAG_A) 26 + 27 + /* GRE is a mess: Four different standards */ 28 + struct gre_hdr { 29 + #if defined(__LITTLE_ENDIAN_BITFIELD) 30 + __u16 rec:3, 31 + srr:1, 32 + seq:1, 33 + key:1, 34 + routing:1, 35 + csum:1, 36 + version:3, 37 + reserved:4, 38 + ack:1; 39 + #elif defined(__BIG_ENDIAN_BITFIELD) 40 + __u16 csum:1, 41 + routing:1, 42 + key:1, 43 + seq:1, 44 + srr:1, 45 + rec:3, 46 + ack:1, 47 + reserved:4, 48 + version:3; 49 + #else 50 + #error "Adjust your <asm/byteorder.h> defines" 51 + #endif 52 + __u16 protocol; 53 + }; 54 + 55 + /* modified GRE header for PPTP */ 56 + struct gre_hdr_pptp { 57 + __u8 flags; /* bitfield */ 58 + __u8 version; /* should be GRE_VERSION_PPTP */ 59 + __u16 protocol; /* should be GRE_PROTOCOL_PPTP */ 60 + __u16 payload_len; /* size of ppp payload, not inc. gre header */ 61 + __u16 call_id; /* peer's call_id for this session */ 62 + __u32 seq; /* sequence number. Present if S==1 */ 63 + __u32 ack; /* seq number of highest packet recieved by */ 64 + /* sender in this session */ 65 + }; 66 + 67 + 68 + /* this is part of ip_conntrack */ 69 + struct ip_ct_gre { 70 + unsigned int stream_timeout; 71 + unsigned int timeout; 72 + }; 73 + 74 + #ifdef __KERNEL__ 75 + struct ip_conntrack_expect; 76 + struct ip_conntrack; 77 + 78 + /* structure for original <-> reply keymap */ 79 + struct ip_ct_gre_keymap { 80 + struct list_head list; 81 + 82 + struct ip_conntrack_tuple tuple; 83 + }; 84 + 85 + /* add new tuple->key_reply pair to keymap */ 86 + int ip_ct_gre_keymap_add(struct ip_conntrack *ct, 87 + struct ip_conntrack_tuple *t, 88 + int reply); 89 + 90 + /* delete keymap entries */ 91 + void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct); 92 + 93 + 94 + /* get pointer to gre key, if present */ 95 + static inline u_int32_t *gre_key(struct gre_hdr *greh) 96 + { 97 + if (!greh->key) 98 + return NULL; 99 + if (greh->csum || greh->routing) 100 + return (u_int32_t *) (greh+sizeof(*greh)+4); 101 + return (u_int32_t *) (greh+sizeof(*greh)); 102 + } 103 + 104 + /* get pointer ot gre csum, if present */ 105 + static inline u_int16_t *gre_csum(struct gre_hdr *greh) 106 + { 107 + if (!greh->csum) 108 + return NULL; 109 + return (u_int16_t *) (greh+sizeof(*greh)); 110 + } 111 + 112 + #endif /* __KERNEL__ */ 113 + 114 + #endif /* _CONNTRACK_PROTO_GRE_H */
+7
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
··· 28 28 struct { 29 29 u_int16_t port; 30 30 } sctp; 31 + struct { 32 + u_int16_t key; /* key is 32bit, pptp only uses 16 */ 33 + } gre; 31 34 }; 32 35 33 36 /* The manipulable part of the tuple. */ ··· 64 61 struct { 65 62 u_int16_t port; 66 63 } sctp; 64 + struct { 65 + u_int16_t key; /* key is 32bit, 66 + * pptp only uses 16 */ 67 + } gre; 67 68 } u; 68 69 69 70 /* The protocol. */
+11
include/linux/netfilter_ipv4/ip_nat_pptp.h
··· 1 + /* PPTP constants and structs */ 2 + #ifndef _NAT_PPTP_H 3 + #define _NAT_PPTP_H 4 + 5 + /* conntrack private data */ 6 + struct ip_nat_pptp { 7 + u_int16_t pns_call_id; /* NAT'ed PNS call id */ 8 + u_int16_t pac_call_id; /* NAT'ed PAC call id */ 9 + }; 10 + 11 + #endif /* _NAT_PPTP_H */
+3
include/linux/netfilter_ipv6/ip6_tables.h
··· 455 455 456 456 /* Check for an extension */ 457 457 extern int ip6t_ext_hdr(u8 nexthdr); 458 + /* find specified header and get offset to it */ 459 + extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 460 + u8 target); 458 461 459 462 #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) 460 463
+1 -1
net/8021q/vlan_dev.c
··· 120 120 unsigned short vid; 121 121 struct net_device_stats *stats; 122 122 unsigned short vlan_TCI; 123 - unsigned short proto; 123 + __be16 proto; 124 124 125 125 /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */ 126 126 vlan_TCI = ntohs(vhdr->h_vlan_TCI);
+17 -17
net/ipv4/fib_trie.c
··· 43 43 * 2 of the License, or (at your option) any later version. 44 44 */ 45 45 46 - #define VERSION "0.403" 46 + #define VERSION "0.404" 47 47 48 48 #include <linux/config.h> 49 49 #include <asm/uaccess.h> ··· 224 224 Consider a node 'n' and its parent 'tp'. 225 225 226 226 If n is a leaf, every bit in its key is significant. Its presence is 227 - necessitaded by path compression, since during a tree traversal (when 227 + necessitated by path compression, since during a tree traversal (when 228 228 searching for a leaf - unless we are doing an insertion) we will completely 229 229 ignore all skipped bits we encounter. Thus we need to verify, at the end of 230 230 a potentially successful search, that we have indeed been walking the ··· 836 836 #endif 837 837 } 838 838 839 - /* readside most use rcu_read_lock currently dump routines 839 + /* readside must use rcu_read_lock currently dump routines 840 840 via get_fa_head and dump */ 841 841 842 - static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen) 842 + static struct leaf_info *find_leaf_info(struct leaf *l, int plen) 843 843 { 844 + struct hlist_head *head = &l->list; 844 845 struct hlist_node *node; 845 846 struct leaf_info *li; 846 847 ··· 854 853 855 854 static inline struct list_head * get_fa_head(struct leaf *l, int plen) 856 855 { 857 - struct leaf_info *li = find_leaf_info(&l->list, plen); 856 + struct leaf_info *li = find_leaf_info(l, plen); 858 857 859 858 if (!li) 860 859 return NULL; ··· 1249 1248 } 1250 1249 1251 1250 1252 - /* should be clalled with rcu_read_lock */ 1251 + /* should be called with rcu_read_lock */ 1253 1252 static inline int check_leaf(struct trie *t, struct leaf *l, 1254 1253 t_key key, int *plen, const struct flowi *flp, 1255 1254 struct fib_result *res) ··· 1591 1590 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req); 1592 1591 1593 1592 l = fib_find_node(t, key); 1594 - li = find_leaf_info(&l->list, plen); 1593 + li = find_leaf_info(l, plen); 1595 1594 1596 1595 list_del_rcu(&fa->fa_list); 1597 1596 ··· 1715 1714 1716 1715 t->revision++; 1717 1716 1718 - rcu_read_lock(); 1719 1717 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { 1720 1718 found += trie_flush_leaf(t, l); 1721 1719 ··· 1722 1722 trie_leaf_remove(t, ll->key); 1723 1723 ll = l; 1724 1724 } 1725 - rcu_read_unlock(); 1726 1725 1727 1726 if (ll && hlist_empty(&ll->list)) 1728 1727 trie_leaf_remove(t, ll->key); ··· 2028 2029 iter->tnode = (struct tnode *) n; 2029 2030 iter->trie = t; 2030 2031 iter->index = 0; 2031 - iter->depth = 0; 2032 + iter->depth = 1; 2032 2033 return n; 2033 2034 } 2034 2035 return NULL; ··· 2273 2274 seq_puts(seq, "<local>:\n"); 2274 2275 else 2275 2276 seq_puts(seq, "<main>:\n"); 2276 - } else { 2277 - seq_indent(seq, iter->depth-1); 2278 - seq_printf(seq, " +-- %d.%d.%d.%d/%d\n", 2279 - NIPQUAD(prf), tn->pos); 2280 - } 2277 + } 2278 + seq_indent(seq, iter->depth-1); 2279 + seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n", 2280 + NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, 2281 + tn->empty_children); 2282 + 2281 2283 } else { 2282 2284 struct leaf *l = (struct leaf *) n; 2283 2285 int i; ··· 2287 2287 seq_indent(seq, iter->depth); 2288 2288 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); 2289 2289 for (i = 32; i >= 0; i--) { 2290 - struct leaf_info *li = find_leaf_info(&l->list, i); 2290 + struct leaf_info *li = find_leaf_info(l, i); 2291 2291 if (li) { 2292 2292 struct fib_alias *fa; 2293 2293 list_for_each_entry_rcu(fa, &li->falh, fa_list) { ··· 2383 2383 return 0; 2384 2384 2385 2385 for (i=32; i>=0; i--) { 2386 - struct leaf_info *li = find_leaf_info(&l->list, i); 2386 + struct leaf_info *li = find_leaf_info(l, i); 2387 2387 struct fib_alias *fa; 2388 2388 u32 mask, prefix; 2389 2389
+22
net/ipv4/netfilter/Kconfig
··· 137 137 138 138 To compile it as a module, choose M here. If unsure, say Y. 139 139 140 + config IP_NF_PPTP 141 + tristate 'PPTP protocol support' 142 + help 143 + This module adds support for PPTP (Point to Point Tunnelling 144 + Protocol, RFC2637) conncection tracking and NAT. 145 + 146 + If you are running PPTP sessions over a stateful firewall or NAT 147 + box, you may want to enable this feature. 148 + 149 + Please note that not all PPTP modes of operation are supported yet. 150 + For more info, read top of the file 151 + net/ipv4/netfilter/ip_conntrack_pptp.c 152 + 153 + If you want to compile it as a module, say M here and read 154 + Documentation/modules.txt. If unsure, say `N'. 155 + 140 156 config IP_NF_QUEUE 141 157 tristate "IP Userspace queueing via NETLINK (OBSOLETE)" 142 158 help ··· 636 620 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n 637 621 default IP_NF_NAT if IP_NF_AMANDA=y 638 622 default m if IP_NF_AMANDA=m 623 + 624 + config IP_NF_NAT_PPTP 625 + tristate 626 + depends on IP_NF_NAT!=n && IP_NF_PPTP!=n 627 + default IP_NF_NAT if IP_NF_PPTP=y 628 + default m if IP_NF_PPTP=m 639 629 640 630 # mangle + specific targets 641 631 config IP_NF_MANGLE
+5
net/ipv4/netfilter/Makefile
··· 6 6 ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o 7 7 iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o 8 8 9 + ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o 10 + ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o 11 + 9 12 # connection tracking 10 13 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o 11 14 ··· 20 17 obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o 21 18 22 19 # connection tracking helpers 20 + obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o 23 21 obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o 24 22 obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o 25 23 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o ··· 28 24 obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o 29 25 30 26 # NAT helpers 27 + obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o 31 28 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o 32 29 obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o 33 30 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
+1 -1
net/ipv4/netfilter/ip_conntrack_core.c
··· 233 233 234 234 /* Just find a expectation corresponding to a tuple. */ 235 235 struct ip_conntrack_expect * 236 - ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) 236 + ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) 237 237 { 238 238 struct ip_conntrack_expect *i; 239 239
+805
net/ipv4/netfilter/ip_conntrack_helper_pptp.c
··· 1 + /* 2 + * ip_conntrack_pptp.c - Version 3.0 3 + * 4 + * Connection tracking support for PPTP (Point to Point Tunneling Protocol). 5 + * PPTP is a a protocol for creating virtual private networks. 6 + * It is a specification defined by Microsoft and some vendors 7 + * working with Microsoft. PPTP is built on top of a modified 8 + * version of the Internet Generic Routing Encapsulation Protocol. 9 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of 10 + * PPTP can be found in RFC 2637 11 + * 12 + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> 13 + * 14 + * Development of this code funded by Astaro AG (http://www.astaro.com/) 15 + * 16 + * Limitations: 17 + * - We blindly assume that control connections are always 18 + * established in PNS->PAC direction. This is a violation 19 + * of RFFC2673 20 + * - We can only support one single call within each session 21 + * 22 + * TODO: 23 + * - testing of incoming PPTP calls 24 + * 25 + * Changes: 26 + * 2002-02-05 - Version 1.3 27 + * - Call ip_conntrack_unexpect_related() from 28 + * pptp_destroy_siblings() to destroy expectations in case 29 + * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen 30 + * (Philip Craig <philipc@snapgear.com>) 31 + * - Add Version information at module loadtime 32 + * 2002-02-10 - Version 1.6 33 + * - move to C99 style initializers 34 + * - remove second expectation if first arrives 35 + * 2004-10-22 - Version 2.0 36 + * - merge Mandrake's 2.6.x port with recent 2.6.x API changes 37 + * - fix lots of linear skb assumptions from Mandrake's port 38 + * 2005-06-10 - Version 2.1 39 + * - use ip_conntrack_expect_free() instead of kfree() on the 40 + * expect's (which are from the slab for quite some time) 41 + * 2005-06-10 - Version 3.0 42 + * - port helper to post-2.6.11 API changes, 43 + * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) 44 + * 2005-07-30 - Version 3.1 45 + * - port helper to 2.6.13 API changes 46 + * 47 + */ 48 + 49 + #include <linux/config.h> 50 + #include <linux/module.h> 51 + #include <linux/netfilter.h> 52 + #include <linux/ip.h> 53 + #include <net/checksum.h> 54 + #include <net/tcp.h> 55 + 56 + #include <linux/netfilter_ipv4/ip_conntrack.h> 57 + #include <linux/netfilter_ipv4/ip_conntrack_core.h> 58 + #include <linux/netfilter_ipv4/ip_conntrack_helper.h> 59 + #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> 60 + #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> 61 + 62 + #define IP_CT_PPTP_VERSION "3.1" 63 + 64 + MODULE_LICENSE("GPL"); 65 + MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); 66 + MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); 67 + 68 + static DEFINE_SPINLOCK(ip_pptp_lock); 69 + 70 + int 71 + (*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, 72 + struct ip_conntrack *ct, 73 + enum ip_conntrack_info ctinfo, 74 + struct PptpControlHeader *ctlh, 75 + union pptp_ctrl_union *pptpReq); 76 + 77 + int 78 + (*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, 79 + struct ip_conntrack *ct, 80 + enum ip_conntrack_info ctinfo, 81 + struct PptpControlHeader *ctlh, 82 + union pptp_ctrl_union *pptpReq); 83 + 84 + int 85 + (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig, 86 + struct ip_conntrack_expect *expect_reply); 87 + 88 + void 89 + (*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, 90 + struct ip_conntrack_expect *exp); 91 + 92 + #if 0 93 + /* PptpControlMessageType names */ 94 + const char *pptp_msg_name[] = { 95 + "UNKNOWN_MESSAGE", 96 + "START_SESSION_REQUEST", 97 + "START_SESSION_REPLY", 98 + "STOP_SESSION_REQUEST", 99 + "STOP_SESSION_REPLY", 100 + "ECHO_REQUEST", 101 + "ECHO_REPLY", 102 + "OUT_CALL_REQUEST", 103 + "OUT_CALL_REPLY", 104 + "IN_CALL_REQUEST", 105 + "IN_CALL_REPLY", 106 + "IN_CALL_CONNECT", 107 + "CALL_CLEAR_REQUEST", 108 + "CALL_DISCONNECT_NOTIFY", 109 + "WAN_ERROR_NOTIFY", 110 + "SET_LINK_INFO" 111 + }; 112 + EXPORT_SYMBOL(pptp_msg_name); 113 + #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) 114 + #else 115 + #define DEBUGP(format, args...) 116 + #endif 117 + 118 + #define SECS *HZ 119 + #define MINS * 60 SECS 120 + #define HOURS * 60 MINS 121 + 122 + #define PPTP_GRE_TIMEOUT (10 MINS) 123 + #define PPTP_GRE_STREAM_TIMEOUT (5 HOURS) 124 + 125 + static void pptp_expectfn(struct ip_conntrack *ct, 126 + struct ip_conntrack_expect *exp) 127 + { 128 + DEBUGP("increasing timeouts\n"); 129 + 130 + /* increase timeout of GRE data channel conntrack entry */ 131 + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; 132 + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; 133 + 134 + /* Can you see how rusty this code is, compared with the pre-2.6.11 135 + * one? That's what happened to my shiny newnat of 2002 ;( -HW */ 136 + 137 + if (!ip_nat_pptp_hook_expectfn) { 138 + struct ip_conntrack_tuple inv_t; 139 + struct ip_conntrack_expect *exp_other; 140 + 141 + /* obviously this tuple inversion only works until you do NAT */ 142 + invert_tuplepr(&inv_t, &exp->tuple); 143 + DEBUGP("trying to unexpect other dir: "); 144 + DUMP_TUPLE(&inv_t); 145 + 146 + exp_other = ip_conntrack_expect_find(&inv_t); 147 + if (exp_other) { 148 + /* delete other expectation. */ 149 + DEBUGP("found\n"); 150 + ip_conntrack_unexpect_related(exp_other); 151 + ip_conntrack_expect_put(exp_other); 152 + } else { 153 + DEBUGP("not found\n"); 154 + } 155 + } else { 156 + /* we need more than simple inversion */ 157 + ip_nat_pptp_hook_expectfn(ct, exp); 158 + } 159 + } 160 + 161 + static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) 162 + { 163 + struct ip_conntrack_tuple_hash *h; 164 + struct ip_conntrack_expect *exp; 165 + 166 + DEBUGP("trying to timeout ct or exp for tuple "); 167 + DUMP_TUPLE(t); 168 + 169 + h = ip_conntrack_find_get(t, NULL); 170 + if (h) { 171 + struct ip_conntrack *sibling = tuplehash_to_ctrack(h); 172 + DEBUGP("setting timeout of conntrack %p to 0\n", sibling); 173 + sibling->proto.gre.timeout = 0; 174 + sibling->proto.gre.stream_timeout = 0; 175 + /* refresh_acct will not modify counters if skb == NULL */ 176 + if (del_timer(&sibling->timeout)) 177 + sibling->timeout.function((unsigned long)sibling); 178 + ip_conntrack_put(sibling); 179 + return 1; 180 + } else { 181 + exp = ip_conntrack_expect_find(t); 182 + if (exp) { 183 + DEBUGP("unexpect_related of expect %p\n", exp); 184 + ip_conntrack_unexpect_related(exp); 185 + ip_conntrack_expect_put(exp); 186 + return 1; 187 + } 188 + } 189 + 190 + return 0; 191 + } 192 + 193 + 194 + /* timeout GRE data connections */ 195 + static void pptp_destroy_siblings(struct ip_conntrack *ct) 196 + { 197 + struct ip_conntrack_tuple t; 198 + 199 + /* Since ct->sibling_list has literally rusted away in 2.6.11, 200 + * we now need another way to find out about our sibling 201 + * contrack and expects... -HW */ 202 + 203 + /* try original (pns->pac) tuple */ 204 + memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); 205 + t.dst.protonum = IPPROTO_GRE; 206 + t.src.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); 207 + t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); 208 + 209 + if (!destroy_sibling_or_exp(&t)) 210 + DEBUGP("failed to timeout original pns->pac ct/exp\n"); 211 + 212 + /* try reply (pac->pns) tuple */ 213 + memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); 214 + t.dst.protonum = IPPROTO_GRE; 215 + t.src.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); 216 + t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); 217 + 218 + if (!destroy_sibling_or_exp(&t)) 219 + DEBUGP("failed to timeout reply pac->pns ct/exp\n"); 220 + } 221 + 222 + /* expect GRE connections (PNS->PAC and PAC->PNS direction) */ 223 + static inline int 224 + exp_gre(struct ip_conntrack *master, 225 + u_int32_t seq, 226 + u_int16_t callid, 227 + u_int16_t peer_callid) 228 + { 229 + struct ip_conntrack_tuple inv_tuple; 230 + struct ip_conntrack_tuple exp_tuples[] = { 231 + /* tuple in original direction, PNS->PAC */ 232 + { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, 233 + .u = { .gre = { .key = peer_callid } } 234 + }, 235 + .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, 236 + .u = { .gre = { .key = callid } }, 237 + .protonum = IPPROTO_GRE 238 + }, 239 + }, 240 + /* tuple in reply direction, PAC->PNS */ 241 + { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, 242 + .u = { .gre = { .key = callid } } 243 + }, 244 + .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip, 245 + .u = { .gre = { .key = peer_callid } }, 246 + .protonum = IPPROTO_GRE 247 + }, 248 + } 249 + }; 250 + struct ip_conntrack_expect *exp_orig, *exp_reply; 251 + int ret = 1; 252 + 253 + exp_orig = ip_conntrack_expect_alloc(master); 254 + if (exp_orig == NULL) 255 + goto out; 256 + 257 + exp_reply = ip_conntrack_expect_alloc(master); 258 + if (exp_reply == NULL) 259 + goto out_put_orig; 260 + 261 + memcpy(&exp_orig->tuple, &exp_tuples[0], sizeof(exp_orig->tuple)); 262 + 263 + exp_orig->mask.src.ip = 0xffffffff; 264 + exp_orig->mask.src.u.all = 0; 265 + exp_orig->mask.dst.u.all = 0; 266 + exp_orig->mask.dst.u.gre.key = 0xffff; 267 + exp_orig->mask.dst.ip = 0xffffffff; 268 + exp_orig->mask.dst.protonum = 0xff; 269 + 270 + exp_orig->master = master; 271 + exp_orig->expectfn = pptp_expectfn; 272 + exp_orig->flags = 0; 273 + 274 + exp_orig->dir = IP_CT_DIR_ORIGINAL; 275 + 276 + /* both expectations are identical apart from tuple */ 277 + memcpy(exp_reply, exp_orig, sizeof(*exp_reply)); 278 + memcpy(&exp_reply->tuple, &exp_tuples[1], sizeof(exp_reply->tuple)); 279 + 280 + exp_reply->dir = !exp_orig->dir; 281 + 282 + if (ip_nat_pptp_hook_exp_gre) 283 + ret = ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); 284 + else { 285 + 286 + DEBUGP("calling expect_related PNS->PAC"); 287 + DUMP_TUPLE(&exp_orig->tuple); 288 + 289 + if (ip_conntrack_expect_related(exp_orig) != 0) { 290 + DEBUGP("cannot expect_related()\n"); 291 + goto out_put_both; 292 + } 293 + 294 + DEBUGP("calling expect_related PAC->PNS"); 295 + DUMP_TUPLE(&exp_reply->tuple); 296 + 297 + if (ip_conntrack_expect_related(exp_reply) != 0) { 298 + DEBUGP("cannot expect_related()\n"); 299 + goto out_unexpect_orig; 300 + } 301 + 302 + /* Add GRE keymap entries */ 303 + if (ip_ct_gre_keymap_add(master, &exp_reply->tuple, 0) != 0) { 304 + DEBUGP("cannot keymap_add() exp\n"); 305 + goto out_unexpect_both; 306 + } 307 + 308 + invert_tuplepr(&inv_tuple, &exp_reply->tuple); 309 + if (ip_ct_gre_keymap_add(master, &inv_tuple, 1) != 0) { 310 + ip_ct_gre_keymap_destroy(master); 311 + DEBUGP("cannot keymap_add() exp_inv\n"); 312 + goto out_unexpect_both; 313 + } 314 + ret = 0; 315 + } 316 + 317 + out_put_both: 318 + ip_conntrack_expect_put(exp_reply); 319 + out_put_orig: 320 + ip_conntrack_expect_put(exp_orig); 321 + out: 322 + return ret; 323 + 324 + out_unexpect_both: 325 + ip_conntrack_unexpect_related(exp_reply); 326 + out_unexpect_orig: 327 + ip_conntrack_unexpect_related(exp_orig); 328 + goto out_put_both; 329 + } 330 + 331 + static inline int 332 + pptp_inbound_pkt(struct sk_buff **pskb, 333 + struct tcphdr *tcph, 334 + unsigned int nexthdr_off, 335 + unsigned int datalen, 336 + struct ip_conntrack *ct, 337 + enum ip_conntrack_info ctinfo) 338 + { 339 + struct PptpControlHeader _ctlh, *ctlh; 340 + unsigned int reqlen; 341 + union pptp_ctrl_union _pptpReq, *pptpReq; 342 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; 343 + u_int16_t msg, *cid, *pcid; 344 + u_int32_t seq; 345 + 346 + ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); 347 + if (!ctlh) { 348 + DEBUGP("error during skb_header_pointer\n"); 349 + return NF_ACCEPT; 350 + } 351 + nexthdr_off += sizeof(_ctlh); 352 + datalen -= sizeof(_ctlh); 353 + 354 + reqlen = datalen; 355 + if (reqlen > sizeof(*pptpReq)) 356 + reqlen = sizeof(*pptpReq); 357 + pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); 358 + if (!pptpReq) { 359 + DEBUGP("error during skb_header_pointer\n"); 360 + return NF_ACCEPT; 361 + } 362 + 363 + msg = ntohs(ctlh->messageType); 364 + DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); 365 + 366 + switch (msg) { 367 + case PPTP_START_SESSION_REPLY: 368 + if (reqlen < sizeof(_pptpReq.srep)) { 369 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 370 + break; 371 + } 372 + 373 + /* server confirms new control session */ 374 + if (info->sstate < PPTP_SESSION_REQUESTED) { 375 + DEBUGP("%s without START_SESS_REQUEST\n", 376 + pptp_msg_name[msg]); 377 + break; 378 + } 379 + if (pptpReq->srep.resultCode == PPTP_START_OK) 380 + info->sstate = PPTP_SESSION_CONFIRMED; 381 + else 382 + info->sstate = PPTP_SESSION_ERROR; 383 + break; 384 + 385 + case PPTP_STOP_SESSION_REPLY: 386 + if (reqlen < sizeof(_pptpReq.strep)) { 387 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 388 + break; 389 + } 390 + 391 + /* server confirms end of control session */ 392 + if (info->sstate > PPTP_SESSION_STOPREQ) { 393 + DEBUGP("%s without STOP_SESS_REQUEST\n", 394 + pptp_msg_name[msg]); 395 + break; 396 + } 397 + if (pptpReq->strep.resultCode == PPTP_STOP_OK) 398 + info->sstate = PPTP_SESSION_NONE; 399 + else 400 + info->sstate = PPTP_SESSION_ERROR; 401 + break; 402 + 403 + case PPTP_OUT_CALL_REPLY: 404 + if (reqlen < sizeof(_pptpReq.ocack)) { 405 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 406 + break; 407 + } 408 + 409 + /* server accepted call, we now expect GRE frames */ 410 + if (info->sstate != PPTP_SESSION_CONFIRMED) { 411 + DEBUGP("%s but no session\n", pptp_msg_name[msg]); 412 + break; 413 + } 414 + if (info->cstate != PPTP_CALL_OUT_REQ && 415 + info->cstate != PPTP_CALL_OUT_CONF) { 416 + DEBUGP("%s without OUTCALL_REQ\n", pptp_msg_name[msg]); 417 + break; 418 + } 419 + if (pptpReq->ocack.resultCode != PPTP_OUTCALL_CONNECT) { 420 + info->cstate = PPTP_CALL_NONE; 421 + break; 422 + } 423 + 424 + cid = &pptpReq->ocack.callID; 425 + pcid = &pptpReq->ocack.peersCallID; 426 + 427 + info->pac_call_id = ntohs(*cid); 428 + 429 + if (htons(info->pns_call_id) != *pcid) { 430 + DEBUGP("%s for unknown callid %u\n", 431 + pptp_msg_name[msg], ntohs(*pcid)); 432 + break; 433 + } 434 + 435 + DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], 436 + ntohs(*cid), ntohs(*pcid)); 437 + 438 + info->cstate = PPTP_CALL_OUT_CONF; 439 + 440 + seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) 441 + + sizeof(struct PptpControlHeader) 442 + + ((void *)pcid - (void *)pptpReq); 443 + 444 + if (exp_gre(ct, seq, *cid, *pcid) != 0) 445 + printk("ip_conntrack_pptp: error during exp_gre\n"); 446 + break; 447 + 448 + case PPTP_IN_CALL_REQUEST: 449 + if (reqlen < sizeof(_pptpReq.icack)) { 450 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 451 + break; 452 + } 453 + 454 + /* server tells us about incoming call request */ 455 + if (info->sstate != PPTP_SESSION_CONFIRMED) { 456 + DEBUGP("%s but no session\n", pptp_msg_name[msg]); 457 + break; 458 + } 459 + pcid = &pptpReq->icack.peersCallID; 460 + DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); 461 + info->cstate = PPTP_CALL_IN_REQ; 462 + info->pac_call_id = ntohs(*pcid); 463 + break; 464 + 465 + case PPTP_IN_CALL_CONNECT: 466 + if (reqlen < sizeof(_pptpReq.iccon)) { 467 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 468 + break; 469 + } 470 + 471 + /* server tells us about incoming call established */ 472 + if (info->sstate != PPTP_SESSION_CONFIRMED) { 473 + DEBUGP("%s but no session\n", pptp_msg_name[msg]); 474 + break; 475 + } 476 + if (info->sstate != PPTP_CALL_IN_REP 477 + && info->sstate != PPTP_CALL_IN_CONF) { 478 + DEBUGP("%s but never sent IN_CALL_REPLY\n", 479 + pptp_msg_name[msg]); 480 + break; 481 + } 482 + 483 + pcid = &pptpReq->iccon.peersCallID; 484 + cid = &info->pac_call_id; 485 + 486 + if (info->pns_call_id != ntohs(*pcid)) { 487 + DEBUGP("%s for unknown CallID %u\n", 488 + pptp_msg_name[msg], ntohs(*cid)); 489 + break; 490 + } 491 + 492 + DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); 493 + info->cstate = PPTP_CALL_IN_CONF; 494 + 495 + /* we expect a GRE connection from PAC to PNS */ 496 + seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) 497 + + sizeof(struct PptpControlHeader) 498 + + ((void *)pcid - (void *)pptpReq); 499 + 500 + if (exp_gre(ct, seq, *cid, *pcid) != 0) 501 + printk("ip_conntrack_pptp: error during exp_gre\n"); 502 + 503 + break; 504 + 505 + case PPTP_CALL_DISCONNECT_NOTIFY: 506 + if (reqlen < sizeof(_pptpReq.disc)) { 507 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 508 + break; 509 + } 510 + 511 + /* server confirms disconnect */ 512 + cid = &pptpReq->disc.callID; 513 + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid)); 514 + info->cstate = PPTP_CALL_NONE; 515 + 516 + /* untrack this call id, unexpect GRE packets */ 517 + pptp_destroy_siblings(ct); 518 + break; 519 + 520 + case PPTP_WAN_ERROR_NOTIFY: 521 + break; 522 + 523 + case PPTP_ECHO_REQUEST: 524 + case PPTP_ECHO_REPLY: 525 + /* I don't have to explain these ;) */ 526 + break; 527 + default: 528 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) 529 + ? pptp_msg_name[msg]:pptp_msg_name[0], msg); 530 + break; 531 + } 532 + 533 + 534 + if (ip_nat_pptp_hook_inbound) 535 + return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, 536 + pptpReq); 537 + 538 + return NF_ACCEPT; 539 + 540 + } 541 + 542 + static inline int 543 + pptp_outbound_pkt(struct sk_buff **pskb, 544 + struct tcphdr *tcph, 545 + unsigned int nexthdr_off, 546 + unsigned int datalen, 547 + struct ip_conntrack *ct, 548 + enum ip_conntrack_info ctinfo) 549 + { 550 + struct PptpControlHeader _ctlh, *ctlh; 551 + unsigned int reqlen; 552 + union pptp_ctrl_union _pptpReq, *pptpReq; 553 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; 554 + u_int16_t msg, *cid, *pcid; 555 + 556 + ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); 557 + if (!ctlh) 558 + return NF_ACCEPT; 559 + nexthdr_off += sizeof(_ctlh); 560 + datalen -= sizeof(_ctlh); 561 + 562 + reqlen = datalen; 563 + if (reqlen > sizeof(*pptpReq)) 564 + reqlen = sizeof(*pptpReq); 565 + pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); 566 + if (!pptpReq) 567 + return NF_ACCEPT; 568 + 569 + msg = ntohs(ctlh->messageType); 570 + DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); 571 + 572 + switch (msg) { 573 + case PPTP_START_SESSION_REQUEST: 574 + /* client requests for new control session */ 575 + if (info->sstate != PPTP_SESSION_NONE) { 576 + DEBUGP("%s but we already have one", 577 + pptp_msg_name[msg]); 578 + } 579 + info->sstate = PPTP_SESSION_REQUESTED; 580 + break; 581 + case PPTP_STOP_SESSION_REQUEST: 582 + /* client requests end of control session */ 583 + info->sstate = PPTP_SESSION_STOPREQ; 584 + break; 585 + 586 + case PPTP_OUT_CALL_REQUEST: 587 + if (reqlen < sizeof(_pptpReq.ocreq)) { 588 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 589 + /* FIXME: break; */ 590 + } 591 + 592 + /* client initiating connection to server */ 593 + if (info->sstate != PPTP_SESSION_CONFIRMED) { 594 + DEBUGP("%s but no session\n", 595 + pptp_msg_name[msg]); 596 + break; 597 + } 598 + info->cstate = PPTP_CALL_OUT_REQ; 599 + /* track PNS call id */ 600 + cid = &pptpReq->ocreq.callID; 601 + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid)); 602 + info->pns_call_id = ntohs(*cid); 603 + break; 604 + case PPTP_IN_CALL_REPLY: 605 + if (reqlen < sizeof(_pptpReq.icack)) { 606 + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); 607 + break; 608 + } 609 + 610 + /* client answers incoming call */ 611 + if (info->cstate != PPTP_CALL_IN_REQ 612 + && info->cstate != PPTP_CALL_IN_REP) { 613 + DEBUGP("%s without incall_req\n", 614 + pptp_msg_name[msg]); 615 + break; 616 + } 617 + if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) { 618 + info->cstate = PPTP_CALL_NONE; 619 + break; 620 + } 621 + pcid = &pptpReq->icack.peersCallID; 622 + if (info->pac_call_id != ntohs(*pcid)) { 623 + DEBUGP("%s for unknown call %u\n", 624 + pptp_msg_name[msg], ntohs(*pcid)); 625 + break; 626 + } 627 + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); 628 + /* part two of the three-way handshake */ 629 + info->cstate = PPTP_CALL_IN_REP; 630 + info->pns_call_id = ntohs(pptpReq->icack.callID); 631 + break; 632 + 633 + case PPTP_CALL_CLEAR_REQUEST: 634 + /* client requests hangup of call */ 635 + if (info->sstate != PPTP_SESSION_CONFIRMED) { 636 + DEBUGP("CLEAR_CALL but no session\n"); 637 + break; 638 + } 639 + /* FUTURE: iterate over all calls and check if 640 + * call ID is valid. We don't do this without newnat, 641 + * because we only know about last call */ 642 + info->cstate = PPTP_CALL_CLEAR_REQ; 643 + break; 644 + case PPTP_SET_LINK_INFO: 645 + break; 646 + case PPTP_ECHO_REQUEST: 647 + case PPTP_ECHO_REPLY: 648 + /* I don't have to explain these ;) */ 649 + break; 650 + default: 651 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? 652 + pptp_msg_name[msg]:pptp_msg_name[0], msg); 653 + /* unknown: no need to create GRE masq table entry */ 654 + break; 655 + } 656 + 657 + if (ip_nat_pptp_hook_outbound) 658 + return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, 659 + pptpReq); 660 + 661 + return NF_ACCEPT; 662 + } 663 + 664 + 665 + /* track caller id inside control connection, call expect_related */ 666 + static int 667 + conntrack_pptp_help(struct sk_buff **pskb, 668 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) 669 + 670 + { 671 + struct pptp_pkt_hdr _pptph, *pptph; 672 + struct tcphdr _tcph, *tcph; 673 + u_int32_t tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; 674 + u_int32_t datalen; 675 + int dir = CTINFO2DIR(ctinfo); 676 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; 677 + unsigned int nexthdr_off; 678 + 679 + int oldsstate, oldcstate; 680 + int ret; 681 + 682 + /* don't do any tracking before tcp handshake complete */ 683 + if (ctinfo != IP_CT_ESTABLISHED 684 + && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { 685 + DEBUGP("ctinfo = %u, skipping\n", ctinfo); 686 + return NF_ACCEPT; 687 + } 688 + 689 + nexthdr_off = (*pskb)->nh.iph->ihl*4; 690 + tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); 691 + BUG_ON(!tcph); 692 + nexthdr_off += tcph->doff * 4; 693 + datalen = tcplen - tcph->doff * 4; 694 + 695 + if (tcph->fin || tcph->rst) { 696 + DEBUGP("RST/FIN received, timeouting GRE\n"); 697 + /* can't do this after real newnat */ 698 + info->cstate = PPTP_CALL_NONE; 699 + 700 + /* untrack this call id, unexpect GRE packets */ 701 + pptp_destroy_siblings(ct); 702 + } 703 + 704 + pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); 705 + if (!pptph) { 706 + DEBUGP("no full PPTP header, can't track\n"); 707 + return NF_ACCEPT; 708 + } 709 + nexthdr_off += sizeof(_pptph); 710 + datalen -= sizeof(_pptph); 711 + 712 + /* if it's not a control message we can't do anything with it */ 713 + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || 714 + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { 715 + DEBUGP("not a control packet\n"); 716 + return NF_ACCEPT; 717 + } 718 + 719 + oldsstate = info->sstate; 720 + oldcstate = info->cstate; 721 + 722 + spin_lock_bh(&ip_pptp_lock); 723 + 724 + /* FIXME: We just blindly assume that the control connection is always 725 + * established from PNS->PAC. However, RFC makes no guarantee */ 726 + if (dir == IP_CT_DIR_ORIGINAL) 727 + /* client -> server (PNS -> PAC) */ 728 + ret = pptp_outbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, 729 + ctinfo); 730 + else 731 + /* server -> client (PAC -> PNS) */ 732 + ret = pptp_inbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, 733 + ctinfo); 734 + DEBUGP("sstate: %d->%d, cstate: %d->%d\n", 735 + oldsstate, info->sstate, oldcstate, info->cstate); 736 + spin_unlock_bh(&ip_pptp_lock); 737 + 738 + return ret; 739 + } 740 + 741 + /* control protocol helper */ 742 + static struct ip_conntrack_helper pptp = { 743 + .list = { NULL, NULL }, 744 + .name = "pptp", 745 + .me = THIS_MODULE, 746 + .max_expected = 2, 747 + .timeout = 5 * 60, 748 + .tuple = { .src = { .ip = 0, 749 + .u = { .tcp = { .port = 750 + __constant_htons(PPTP_CONTROL_PORT) } } 751 + }, 752 + .dst = { .ip = 0, 753 + .u = { .all = 0 }, 754 + .protonum = IPPROTO_TCP 755 + } 756 + }, 757 + .mask = { .src = { .ip = 0, 758 + .u = { .tcp = { .port = 0xffff } } 759 + }, 760 + .dst = { .ip = 0, 761 + .u = { .all = 0 }, 762 + .protonum = 0xff 763 + } 764 + }, 765 + .help = conntrack_pptp_help 766 + }; 767 + 768 + extern void __exit ip_ct_proto_gre_fini(void); 769 + extern int __init ip_ct_proto_gre_init(void); 770 + 771 + /* ip_conntrack_pptp initialization */ 772 + static int __init init(void) 773 + { 774 + int retcode; 775 + 776 + retcode = ip_ct_proto_gre_init(); 777 + if (retcode < 0) 778 + return retcode; 779 + 780 + DEBUGP(" registering helper\n"); 781 + if ((retcode = ip_conntrack_helper_register(&pptp))) { 782 + printk(KERN_ERR "Unable to register conntrack application " 783 + "helper for pptp: %d\n", retcode); 784 + ip_ct_proto_gre_fini(); 785 + return retcode; 786 + } 787 + 788 + printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); 789 + return 0; 790 + } 791 + 792 + static void __exit fini(void) 793 + { 794 + ip_conntrack_helper_unregister(&pptp); 795 + ip_ct_proto_gre_fini(); 796 + printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); 797 + } 798 + 799 + module_init(init); 800 + module_exit(fini); 801 + 802 + EXPORT_SYMBOL(ip_nat_pptp_hook_outbound); 803 + EXPORT_SYMBOL(ip_nat_pptp_hook_inbound); 804 + EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre); 805 + EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn);
+2 -2
net/ipv4/netfilter/ip_conntrack_netlink.c
··· 1270 1270 if (err < 0) 1271 1271 return err; 1272 1272 1273 - exp = ip_conntrack_expect_find_get(&tuple); 1273 + exp = ip_conntrack_expect_find(&tuple); 1274 1274 if (!exp) 1275 1275 return -ENOENT; 1276 1276 ··· 1318 1318 return err; 1319 1319 1320 1320 /* bump usage count to 2 */ 1321 - exp = ip_conntrack_expect_find_get(&tuple); 1321 + exp = ip_conntrack_expect_find(&tuple); 1322 1322 if (!exp) 1323 1323 return -ENOENT; 1324 1324
+327
net/ipv4/netfilter/ip_conntrack_proto_gre.c
··· 1 + /* 2 + * ip_conntrack_proto_gre.c - Version 3.0 3 + * 4 + * Connection tracking protocol helper module for GRE. 5 + * 6 + * GRE is a generic encapsulation protocol, which is generally not very 7 + * suited for NAT, as it has no protocol-specific part as port numbers. 8 + * 9 + * It has an optional key field, which may help us distinguishing two 10 + * connections between the same two hosts. 11 + * 12 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 13 + * 14 + * PPTP is built on top of a modified version of GRE, and has a mandatory 15 + * field called "CallID", which serves us for the same purpose as the key 16 + * field in plain GRE. 17 + * 18 + * Documentation about PPTP can be found in RFC 2637 19 + * 20 + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> 21 + * 22 + * Development of this code funded by Astaro AG (http://www.astaro.com/) 23 + * 24 + */ 25 + 26 + #include <linux/config.h> 27 + #include <linux/module.h> 28 + #include <linux/types.h> 29 + #include <linux/timer.h> 30 + #include <linux/netfilter.h> 31 + #include <linux/ip.h> 32 + #include <linux/in.h> 33 + #include <linux/list.h> 34 + 35 + static DEFINE_RWLOCK(ip_ct_gre_lock); 36 + #define ASSERT_READ_LOCK(x) 37 + #define ASSERT_WRITE_LOCK(x) 38 + 39 + #include <linux/netfilter_ipv4/listhelp.h> 40 + #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> 41 + #include <linux/netfilter_ipv4/ip_conntrack_helper.h> 42 + #include <linux/netfilter_ipv4/ip_conntrack_core.h> 43 + 44 + #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> 45 + #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> 46 + 47 + MODULE_LICENSE("GPL"); 48 + MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); 49 + MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); 50 + 51 + /* shamelessly stolen from ip_conntrack_proto_udp.c */ 52 + #define GRE_TIMEOUT (30*HZ) 53 + #define GRE_STREAM_TIMEOUT (180*HZ) 54 + 55 + #if 0 56 + #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) 57 + #define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \ 58 + NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \ 59 + NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key)) 60 + #else 61 + #define DEBUGP(x, args...) 62 + #define DUMP_TUPLE_GRE(x) 63 + #endif 64 + 65 + /* GRE KEYMAP HANDLING FUNCTIONS */ 66 + static LIST_HEAD(gre_keymap_list); 67 + 68 + static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, 69 + const struct ip_conntrack_tuple *t) 70 + { 71 + return ((km->tuple.src.ip == t->src.ip) && 72 + (km->tuple.dst.ip == t->dst.ip) && 73 + (km->tuple.dst.protonum == t->dst.protonum) && 74 + (km->tuple.dst.u.all == t->dst.u.all)); 75 + } 76 + 77 + /* look up the source key for a given tuple */ 78 + static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) 79 + { 80 + struct ip_ct_gre_keymap *km; 81 + u_int32_t key = 0; 82 + 83 + read_lock_bh(&ip_ct_gre_lock); 84 + km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, 85 + struct ip_ct_gre_keymap *, t); 86 + if (km) 87 + key = km->tuple.src.u.gre.key; 88 + read_unlock_bh(&ip_ct_gre_lock); 89 + 90 + DEBUGP("lookup src key 0x%x up key for ", key); 91 + DUMP_TUPLE_GRE(t); 92 + 93 + return key; 94 + } 95 + 96 + /* add a single keymap entry, associate with specified master ct */ 97 + int 98 + ip_ct_gre_keymap_add(struct ip_conntrack *ct, 99 + struct ip_conntrack_tuple *t, int reply) 100 + { 101 + struct ip_ct_gre_keymap **exist_km, *km, *old; 102 + 103 + if (!ct->helper || strcmp(ct->helper->name, "pptp")) { 104 + DEBUGP("refusing to add GRE keymap to non-pptp session\n"); 105 + return -1; 106 + } 107 + 108 + if (!reply) 109 + exist_km = &ct->help.ct_pptp_info.keymap_orig; 110 + else 111 + exist_km = &ct->help.ct_pptp_info.keymap_reply; 112 + 113 + if (*exist_km) { 114 + /* check whether it's a retransmission */ 115 + old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, 116 + struct ip_ct_gre_keymap *, t); 117 + if (old == *exist_km) { 118 + DEBUGP("retransmission\n"); 119 + return 0; 120 + } 121 + 122 + DEBUGP("trying to override keymap_%s for ct %p\n", 123 + reply? "reply":"orig", ct); 124 + return -EEXIST; 125 + } 126 + 127 + km = kmalloc(sizeof(*km), GFP_ATOMIC); 128 + if (!km) 129 + return -ENOMEM; 130 + 131 + memcpy(&km->tuple, t, sizeof(*t)); 132 + *exist_km = km; 133 + 134 + DEBUGP("adding new entry %p: ", km); 135 + DUMP_TUPLE_GRE(&km->tuple); 136 + 137 + write_lock_bh(&ip_ct_gre_lock); 138 + list_append(&gre_keymap_list, km); 139 + write_unlock_bh(&ip_ct_gre_lock); 140 + 141 + return 0; 142 + } 143 + 144 + /* destroy the keymap entries associated with specified master ct */ 145 + void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct) 146 + { 147 + DEBUGP("entering for ct %p\n", ct); 148 + 149 + if (!ct->helper || strcmp(ct->helper->name, "pptp")) { 150 + DEBUGP("refusing to destroy GRE keymap to non-pptp session\n"); 151 + return; 152 + } 153 + 154 + write_lock_bh(&ip_ct_gre_lock); 155 + if (ct->help.ct_pptp_info.keymap_orig) { 156 + DEBUGP("removing %p from list\n", 157 + ct->help.ct_pptp_info.keymap_orig); 158 + list_del(&ct->help.ct_pptp_info.keymap_orig->list); 159 + kfree(ct->help.ct_pptp_info.keymap_orig); 160 + ct->help.ct_pptp_info.keymap_orig = NULL; 161 + } 162 + if (ct->help.ct_pptp_info.keymap_reply) { 163 + DEBUGP("removing %p from list\n", 164 + ct->help.ct_pptp_info.keymap_reply); 165 + list_del(&ct->help.ct_pptp_info.keymap_reply->list); 166 + kfree(ct->help.ct_pptp_info.keymap_reply); 167 + ct->help.ct_pptp_info.keymap_reply = NULL; 168 + } 169 + write_unlock_bh(&ip_ct_gre_lock); 170 + } 171 + 172 + 173 + /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ 174 + 175 + /* invert gre part of tuple */ 176 + static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, 177 + const struct ip_conntrack_tuple *orig) 178 + { 179 + tuple->dst.u.gre.key = orig->src.u.gre.key; 180 + tuple->src.u.gre.key = orig->dst.u.gre.key; 181 + 182 + return 1; 183 + } 184 + 185 + /* gre hdr info to tuple */ 186 + static int gre_pkt_to_tuple(const struct sk_buff *skb, 187 + unsigned int dataoff, 188 + struct ip_conntrack_tuple *tuple) 189 + { 190 + struct gre_hdr_pptp _pgrehdr, *pgrehdr; 191 + u_int32_t srckey; 192 + struct gre_hdr _grehdr, *grehdr; 193 + 194 + /* first only delinearize old RFC1701 GRE header */ 195 + grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); 196 + if (!grehdr || grehdr->version != GRE_VERSION_PPTP) { 197 + /* try to behave like "ip_conntrack_proto_generic" */ 198 + tuple->src.u.all = 0; 199 + tuple->dst.u.all = 0; 200 + return 1; 201 + } 202 + 203 + /* PPTP header is variable length, only need up to the call_id field */ 204 + pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); 205 + if (!pgrehdr) 206 + return 1; 207 + 208 + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { 209 + DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); 210 + return 0; 211 + } 212 + 213 + tuple->dst.u.gre.key = pgrehdr->call_id; 214 + srckey = gre_keymap_lookup(tuple); 215 + tuple->src.u.gre.key = srckey; 216 + 217 + return 1; 218 + } 219 + 220 + /* print gre part of tuple */ 221 + static int gre_print_tuple(struct seq_file *s, 222 + const struct ip_conntrack_tuple *tuple) 223 + { 224 + return seq_printf(s, "srckey=0x%x dstkey=0x%x ", 225 + ntohs(tuple->src.u.gre.key), 226 + ntohs(tuple->dst.u.gre.key)); 227 + } 228 + 229 + /* print private data for conntrack */ 230 + static int gre_print_conntrack(struct seq_file *s, 231 + const struct ip_conntrack *ct) 232 + { 233 + return seq_printf(s, "timeout=%u, stream_timeout=%u ", 234 + (ct->proto.gre.timeout / HZ), 235 + (ct->proto.gre.stream_timeout / HZ)); 236 + } 237 + 238 + /* Returns verdict for packet, and may modify conntrack */ 239 + static int gre_packet(struct ip_conntrack *ct, 240 + const struct sk_buff *skb, 241 + enum ip_conntrack_info conntrackinfo) 242 + { 243 + /* If we've seen traffic both ways, this is a GRE connection. 244 + * Extend timeout. */ 245 + if (ct->status & IPS_SEEN_REPLY) { 246 + ip_ct_refresh_acct(ct, conntrackinfo, skb, 247 + ct->proto.gre.stream_timeout); 248 + /* Also, more likely to be important, and not a probe. */ 249 + set_bit(IPS_ASSURED_BIT, &ct->status); 250 + } else 251 + ip_ct_refresh_acct(ct, conntrackinfo, skb, 252 + ct->proto.gre.timeout); 253 + 254 + return NF_ACCEPT; 255 + } 256 + 257 + /* Called when a new connection for this protocol found. */ 258 + static int gre_new(struct ip_conntrack *ct, 259 + const struct sk_buff *skb) 260 + { 261 + DEBUGP(": "); 262 + DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 263 + 264 + /* initialize to sane value. Ideally a conntrack helper 265 + * (e.g. in case of pptp) is increasing them */ 266 + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; 267 + ct->proto.gre.timeout = GRE_TIMEOUT; 268 + 269 + return 1; 270 + } 271 + 272 + /* Called when a conntrack entry has already been removed from the hashes 273 + * and is about to be deleted from memory */ 274 + static void gre_destroy(struct ip_conntrack *ct) 275 + { 276 + struct ip_conntrack *master = ct->master; 277 + DEBUGP(" entering\n"); 278 + 279 + if (!master) 280 + DEBUGP("no master !?!\n"); 281 + else 282 + ip_ct_gre_keymap_destroy(master); 283 + } 284 + 285 + /* protocol helper struct */ 286 + static struct ip_conntrack_protocol gre = { 287 + .proto = IPPROTO_GRE, 288 + .name = "gre", 289 + .pkt_to_tuple = gre_pkt_to_tuple, 290 + .invert_tuple = gre_invert_tuple, 291 + .print_tuple = gre_print_tuple, 292 + .print_conntrack = gre_print_conntrack, 293 + .packet = gre_packet, 294 + .new = gre_new, 295 + .destroy = gre_destroy, 296 + .me = THIS_MODULE, 297 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 298 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 299 + .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, 300 + .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, 301 + #endif 302 + }; 303 + 304 + /* ip_conntrack_proto_gre initialization */ 305 + int __init ip_ct_proto_gre_init(void) 306 + { 307 + return ip_conntrack_protocol_register(&gre); 308 + } 309 + 310 + void __exit ip_ct_proto_gre_fini(void) 311 + { 312 + struct list_head *pos, *n; 313 + 314 + /* delete all keymap entries */ 315 + write_lock_bh(&ip_ct_gre_lock); 316 + list_for_each_safe(pos, n, &gre_keymap_list) { 317 + DEBUGP("deleting keymap %p at module unload time\n", pos); 318 + list_del(pos); 319 + kfree(pos); 320 + } 321 + write_unlock_bh(&ip_ct_gre_lock); 322 + 323 + ip_conntrack_protocol_unregister(&gre); 324 + } 325 + 326 + EXPORT_SYMBOL(ip_ct_gre_keymap_add); 327 + EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
+2 -2
net/ipv4/netfilter/ip_conntrack_standalone.c
··· 993 993 994 994 EXPORT_SYMBOL(ip_conntrack_expect_alloc); 995 995 EXPORT_SYMBOL(ip_conntrack_expect_put); 996 - EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); 996 + EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); 997 + EXPORT_SYMBOL_GPL(ip_conntrack_expect_find); 997 998 EXPORT_SYMBOL(ip_conntrack_expect_related); 998 999 EXPORT_SYMBOL(ip_conntrack_unexpect_related); 999 1000 EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); 1000 - EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); 1001 1001 EXPORT_SYMBOL_GPL(ip_ct_unlink_expect); 1002 1002 1003 1003 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
+2
net/ipv4/netfilter/ip_nat_core.c
··· 578 578 579 579 return ret; 580 580 } 581 + EXPORT_SYMBOL_GPL(ip_nat_port_nfattr_to_range); 582 + EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr); 581 583 #endif 582 584 583 585 int __init ip_nat_init(void)
+401
net/ipv4/netfilter/ip_nat_helper_pptp.c
··· 1 + /* 2 + * ip_nat_pptp.c - Version 3.0 3 + * 4 + * NAT support for PPTP (Point to Point Tunneling Protocol). 5 + * PPTP is a a protocol for creating virtual private networks. 6 + * It is a specification defined by Microsoft and some vendors 7 + * working with Microsoft. PPTP is built on top of a modified 8 + * version of the Internet Generic Routing Encapsulation Protocol. 9 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of 10 + * PPTP can be found in RFC 2637 11 + * 12 + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> 13 + * 14 + * Development of this code funded by Astaro AG (http://www.astaro.com/) 15 + * 16 + * TODO: - NAT to a unique tuple, not to TCP source port 17 + * (needs netfilter tuple reservation) 18 + * 19 + * Changes: 20 + * 2002-02-10 - Version 1.3 21 + * - Use ip_nat_mangle_tcp_packet() because of cloned skb's 22 + * in local connections (Philip Craig <philipc@snapgear.com>) 23 + * - add checks for magicCookie and pptp version 24 + * - make argument list of pptp_{out,in}bound_packet() shorter 25 + * - move to C99 style initializers 26 + * - print version number at module loadtime 27 + * 2003-09-22 - Version 1.5 28 + * - use SNATed tcp sourceport as callid, since we get called before 29 + * TCP header is mangled (Philip Craig <philipc@snapgear.com>) 30 + * 2004-10-22 - Version 2.0 31 + * - kernel 2.6.x version 32 + * 2005-06-10 - Version 3.0 33 + * - kernel >= 2.6.11 version, 34 + * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) 35 + * 36 + */ 37 + 38 + #include <linux/config.h> 39 + #include <linux/module.h> 40 + #include <linux/ip.h> 41 + #include <linux/tcp.h> 42 + #include <net/tcp.h> 43 + 44 + #include <linux/netfilter_ipv4/ip_nat.h> 45 + #include <linux/netfilter_ipv4/ip_nat_rule.h> 46 + #include <linux/netfilter_ipv4/ip_nat_helper.h> 47 + #include <linux/netfilter_ipv4/ip_nat_pptp.h> 48 + #include <linux/netfilter_ipv4/ip_conntrack_core.h> 49 + #include <linux/netfilter_ipv4/ip_conntrack_helper.h> 50 + #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> 51 + #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> 52 + 53 + #define IP_NAT_PPTP_VERSION "3.0" 54 + 55 + MODULE_LICENSE("GPL"); 56 + MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); 57 + MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); 58 + 59 + 60 + #if 0 61 + extern const char *pptp_msg_name[]; 62 + #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ 63 + __FUNCTION__, ## args) 64 + #else 65 + #define DEBUGP(format, args...) 66 + #endif 67 + 68 + static void pptp_nat_expected(struct ip_conntrack *ct, 69 + struct ip_conntrack_expect *exp) 70 + { 71 + struct ip_conntrack *master = ct->master; 72 + struct ip_conntrack_expect *other_exp; 73 + struct ip_conntrack_tuple t; 74 + struct ip_ct_pptp_master *ct_pptp_info; 75 + struct ip_nat_pptp *nat_pptp_info; 76 + 77 + ct_pptp_info = &master->help.ct_pptp_info; 78 + nat_pptp_info = &master->nat.help.nat_pptp_info; 79 + 80 + /* And here goes the grand finale of corrosion... */ 81 + 82 + if (exp->dir == IP_CT_DIR_ORIGINAL) { 83 + DEBUGP("we are PNS->PAC\n"); 84 + /* therefore, build tuple for PAC->PNS */ 85 + t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; 86 + t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id); 87 + t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; 88 + t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id); 89 + t.dst.protonum = IPPROTO_GRE; 90 + } else { 91 + DEBUGP("we are PAC->PNS\n"); 92 + /* build tuple for PNS->PAC */ 93 + t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; 94 + t.src.u.gre.key = 95 + htons(master->nat.help.nat_pptp_info.pns_call_id); 96 + t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; 97 + t.dst.u.gre.key = 98 + htons(master->nat.help.nat_pptp_info.pac_call_id); 99 + t.dst.protonum = IPPROTO_GRE; 100 + } 101 + 102 + DEBUGP("trying to unexpect other dir: "); 103 + DUMP_TUPLE(&t); 104 + other_exp = ip_conntrack_expect_find(&t); 105 + if (other_exp) { 106 + ip_conntrack_unexpect_related(other_exp); 107 + ip_conntrack_expect_put(other_exp); 108 + DEBUGP("success\n"); 109 + } else { 110 + DEBUGP("not found!\n"); 111 + } 112 + 113 + ip_nat_follow_master(ct, exp); 114 + } 115 + 116 + /* outbound packets == from PNS to PAC */ 117 + static int 118 + pptp_outbound_pkt(struct sk_buff **pskb, 119 + struct ip_conntrack *ct, 120 + enum ip_conntrack_info ctinfo, 121 + struct PptpControlHeader *ctlh, 122 + union pptp_ctrl_union *pptpReq) 123 + 124 + { 125 + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; 126 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; 127 + 128 + u_int16_t msg, *cid = NULL, new_callid; 129 + 130 + new_callid = htons(ct_pptp_info->pns_call_id); 131 + 132 + switch (msg = ntohs(ctlh->messageType)) { 133 + case PPTP_OUT_CALL_REQUEST: 134 + cid = &pptpReq->ocreq.callID; 135 + /* FIXME: ideally we would want to reserve a call ID 136 + * here. current netfilter NAT core is not able to do 137 + * this :( For now we use TCP source port. This breaks 138 + * multiple calls within one control session */ 139 + 140 + /* save original call ID in nat_info */ 141 + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; 142 + 143 + /* don't use tcph->source since we are at a DSTmanip 144 + * hook (e.g. PREROUTING) and pkt is not mangled yet */ 145 + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; 146 + 147 + /* save new call ID in ct info */ 148 + ct_pptp_info->pns_call_id = ntohs(new_callid); 149 + break; 150 + case PPTP_IN_CALL_REPLY: 151 + cid = &pptpReq->icreq.callID; 152 + break; 153 + case PPTP_CALL_CLEAR_REQUEST: 154 + cid = &pptpReq->clrreq.callID; 155 + break; 156 + default: 157 + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, 158 + (msg <= PPTP_MSG_MAX)? 159 + pptp_msg_name[msg]:pptp_msg_name[0]); 160 + /* fall through */ 161 + 162 + case PPTP_SET_LINK_INFO: 163 + /* only need to NAT in case PAC is behind NAT box */ 164 + case PPTP_START_SESSION_REQUEST: 165 + case PPTP_START_SESSION_REPLY: 166 + case PPTP_STOP_SESSION_REQUEST: 167 + case PPTP_STOP_SESSION_REPLY: 168 + case PPTP_ECHO_REQUEST: 169 + case PPTP_ECHO_REPLY: 170 + /* no need to alter packet */ 171 + return NF_ACCEPT; 172 + } 173 + 174 + /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass 175 + * down to here */ 176 + 177 + IP_NF_ASSERT(cid); 178 + 179 + DEBUGP("altering call id from 0x%04x to 0x%04x\n", 180 + ntohs(*cid), ntohs(new_callid)); 181 + 182 + /* mangle packet */ 183 + if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 184 + (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 185 + sizeof(new_callid), 186 + (char *)&new_callid, 187 + sizeof(new_callid)) == 0) 188 + return NF_DROP; 189 + 190 + return NF_ACCEPT; 191 + } 192 + 193 + static int 194 + pptp_exp_gre(struct ip_conntrack_expect *expect_orig, 195 + struct ip_conntrack_expect *expect_reply) 196 + { 197 + struct ip_ct_pptp_master *ct_pptp_info = 198 + &expect_orig->master->help.ct_pptp_info; 199 + struct ip_nat_pptp *nat_pptp_info = 200 + &expect_orig->master->nat.help.nat_pptp_info; 201 + 202 + struct ip_conntrack *ct = expect_orig->master; 203 + 204 + struct ip_conntrack_tuple inv_t; 205 + struct ip_conntrack_tuple *orig_t, *reply_t; 206 + 207 + /* save original PAC call ID in nat_info */ 208 + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; 209 + 210 + /* alter expectation */ 211 + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 212 + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; 213 + 214 + /* alter expectation for PNS->PAC direction */ 215 + invert_tuplepr(&inv_t, &expect_orig->tuple); 216 + expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id); 217 + expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id); 218 + expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); 219 + inv_t.src.ip = reply_t->src.ip; 220 + inv_t.dst.ip = reply_t->dst.ip; 221 + inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id); 222 + inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); 223 + 224 + if (!ip_conntrack_expect_related(expect_orig)) { 225 + DEBUGP("successfully registered expect\n"); 226 + } else { 227 + DEBUGP("can't expect_related(expect_orig)\n"); 228 + return 1; 229 + } 230 + 231 + /* alter expectation for PAC->PNS direction */ 232 + invert_tuplepr(&inv_t, &expect_reply->tuple); 233 + expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id); 234 + expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id); 235 + expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); 236 + inv_t.src.ip = orig_t->src.ip; 237 + inv_t.dst.ip = orig_t->dst.ip; 238 + inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id); 239 + inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); 240 + 241 + if (!ip_conntrack_expect_related(expect_reply)) { 242 + DEBUGP("successfully registered expect\n"); 243 + } else { 244 + DEBUGP("can't expect_related(expect_reply)\n"); 245 + ip_conntrack_unexpect_related(expect_orig); 246 + return 1; 247 + } 248 + 249 + if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) { 250 + DEBUGP("can't register original keymap\n"); 251 + ip_conntrack_unexpect_related(expect_orig); 252 + ip_conntrack_unexpect_related(expect_reply); 253 + return 1; 254 + } 255 + 256 + if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) { 257 + DEBUGP("can't register reply keymap\n"); 258 + ip_conntrack_unexpect_related(expect_orig); 259 + ip_conntrack_unexpect_related(expect_reply); 260 + ip_ct_gre_keymap_destroy(ct); 261 + return 1; 262 + } 263 + 264 + return 0; 265 + } 266 + 267 + /* inbound packets == from PAC to PNS */ 268 + static int 269 + pptp_inbound_pkt(struct sk_buff **pskb, 270 + struct ip_conntrack *ct, 271 + enum ip_conntrack_info ctinfo, 272 + struct PptpControlHeader *ctlh, 273 + union pptp_ctrl_union *pptpReq) 274 + { 275 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; 276 + u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; 277 + 278 + int ret = NF_ACCEPT, rv; 279 + 280 + new_pcid = htons(nat_pptp_info->pns_call_id); 281 + 282 + switch (msg = ntohs(ctlh->messageType)) { 283 + case PPTP_OUT_CALL_REPLY: 284 + pcid = &pptpReq->ocack.peersCallID; 285 + cid = &pptpReq->ocack.callID; 286 + break; 287 + case PPTP_IN_CALL_CONNECT: 288 + pcid = &pptpReq->iccon.peersCallID; 289 + break; 290 + case PPTP_IN_CALL_REQUEST: 291 + /* only need to nat in case PAC is behind NAT box */ 292 + break; 293 + case PPTP_WAN_ERROR_NOTIFY: 294 + pcid = &pptpReq->wanerr.peersCallID; 295 + break; 296 + case PPTP_CALL_DISCONNECT_NOTIFY: 297 + pcid = &pptpReq->disc.callID; 298 + break; 299 + case PPTP_SET_LINK_INFO: 300 + pcid = &pptpReq->setlink.peersCallID; 301 + break; 302 + 303 + default: 304 + DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? 305 + pptp_msg_name[msg]:pptp_msg_name[0]); 306 + /* fall through */ 307 + 308 + case PPTP_START_SESSION_REQUEST: 309 + case PPTP_START_SESSION_REPLY: 310 + case PPTP_STOP_SESSION_REQUEST: 311 + case PPTP_STOP_SESSION_REPLY: 312 + case PPTP_ECHO_REQUEST: 313 + case PPTP_ECHO_REPLY: 314 + /* no need to alter packet */ 315 + return NF_ACCEPT; 316 + } 317 + 318 + /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, 319 + * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ 320 + 321 + /* mangle packet */ 322 + IP_NF_ASSERT(pcid); 323 + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", 324 + ntohs(*pcid), ntohs(new_pcid)); 325 + 326 + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 327 + (void *)pcid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 328 + sizeof(new_pcid), (char *)&new_pcid, 329 + sizeof(new_pcid)); 330 + if (rv != NF_ACCEPT) 331 + return rv; 332 + 333 + if (new_cid) { 334 + IP_NF_ASSERT(cid); 335 + DEBUGP("altering call id from 0x%04x to 0x%04x\n", 336 + ntohs(*cid), ntohs(new_cid)); 337 + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 338 + (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 339 + sizeof(new_cid), 340 + (char *)&new_cid, 341 + sizeof(new_cid)); 342 + if (rv != NF_ACCEPT) 343 + return rv; 344 + } 345 + 346 + /* check for earlier return value of 'switch' above */ 347 + if (ret != NF_ACCEPT) 348 + return ret; 349 + 350 + /* great, at least we don't need to resize packets */ 351 + return NF_ACCEPT; 352 + } 353 + 354 + 355 + extern int __init ip_nat_proto_gre_init(void); 356 + extern void __exit ip_nat_proto_gre_fini(void); 357 + 358 + static int __init init(void) 359 + { 360 + int ret; 361 + 362 + DEBUGP("%s: registering NAT helper\n", __FILE__); 363 + 364 + ret = ip_nat_proto_gre_init(); 365 + if (ret < 0) 366 + return ret; 367 + 368 + BUG_ON(ip_nat_pptp_hook_outbound); 369 + ip_nat_pptp_hook_outbound = &pptp_outbound_pkt; 370 + 371 + BUG_ON(ip_nat_pptp_hook_inbound); 372 + ip_nat_pptp_hook_inbound = &pptp_inbound_pkt; 373 + 374 + BUG_ON(ip_nat_pptp_hook_exp_gre); 375 + ip_nat_pptp_hook_exp_gre = &pptp_exp_gre; 376 + 377 + BUG_ON(ip_nat_pptp_hook_expectfn); 378 + ip_nat_pptp_hook_expectfn = &pptp_nat_expected; 379 + 380 + printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); 381 + return 0; 382 + } 383 + 384 + static void __exit fini(void) 385 + { 386 + DEBUGP("cleanup_module\n" ); 387 + 388 + ip_nat_pptp_hook_expectfn = NULL; 389 + ip_nat_pptp_hook_exp_gre = NULL; 390 + ip_nat_pptp_hook_inbound = NULL; 391 + ip_nat_pptp_hook_outbound = NULL; 392 + 393 + ip_nat_proto_gre_fini(); 394 + /* Make sure noone calls it, meanwhile */ 395 + synchronize_net(); 396 + 397 + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); 398 + } 399 + 400 + module_init(init); 401 + module_exit(fini);
+214
net/ipv4/netfilter/ip_nat_proto_gre.c
··· 1 + /* 2 + * ip_nat_proto_gre.c - Version 2.0 3 + * 4 + * NAT protocol helper module for GRE. 5 + * 6 + * GRE is a generic encapsulation protocol, which is generally not very 7 + * suited for NAT, as it has no protocol-specific part as port numbers. 8 + * 9 + * It has an optional key field, which may help us distinguishing two 10 + * connections between the same two hosts. 11 + * 12 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 13 + * 14 + * PPTP is built on top of a modified version of GRE, and has a mandatory 15 + * field called "CallID", which serves us for the same purpose as the key 16 + * field in plain GRE. 17 + * 18 + * Documentation about PPTP can be found in RFC 2637 19 + * 20 + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> 21 + * 22 + * Development of this code funded by Astaro AG (http://www.astaro.com/) 23 + * 24 + */ 25 + 26 + #include <linux/config.h> 27 + #include <linux/module.h> 28 + #include <linux/ip.h> 29 + #include <linux/netfilter_ipv4/ip_nat.h> 30 + #include <linux/netfilter_ipv4/ip_nat_rule.h> 31 + #include <linux/netfilter_ipv4/ip_nat_protocol.h> 32 + #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> 33 + 34 + MODULE_LICENSE("GPL"); 35 + MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); 36 + MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); 37 + 38 + #if 0 39 + #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ 40 + __FUNCTION__, ## args) 41 + #else 42 + #define DEBUGP(x, args...) 43 + #endif 44 + 45 + /* is key in given range between min and max */ 46 + static int 47 + gre_in_range(const struct ip_conntrack_tuple *tuple, 48 + enum ip_nat_manip_type maniptype, 49 + const union ip_conntrack_manip_proto *min, 50 + const union ip_conntrack_manip_proto *max) 51 + { 52 + u_int32_t key; 53 + 54 + if (maniptype == IP_NAT_MANIP_SRC) 55 + key = tuple->src.u.gre.key; 56 + else 57 + key = tuple->dst.u.gre.key; 58 + 59 + return ntohl(key) >= ntohl(min->gre.key) 60 + && ntohl(key) <= ntohl(max->gre.key); 61 + } 62 + 63 + /* generate unique tuple ... */ 64 + static int 65 + gre_unique_tuple(struct ip_conntrack_tuple *tuple, 66 + const struct ip_nat_range *range, 67 + enum ip_nat_manip_type maniptype, 68 + const struct ip_conntrack *conntrack) 69 + { 70 + static u_int16_t key; 71 + u_int16_t *keyptr; 72 + unsigned int min, i, range_size; 73 + 74 + if (maniptype == IP_NAT_MANIP_SRC) 75 + keyptr = &tuple->src.u.gre.key; 76 + else 77 + keyptr = &tuple->dst.u.gre.key; 78 + 79 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { 80 + DEBUGP("%p: NATing GRE PPTP\n", conntrack); 81 + min = 1; 82 + range_size = 0xffff; 83 + } else { 84 + min = ntohl(range->min.gre.key); 85 + range_size = ntohl(range->max.gre.key) - min + 1; 86 + } 87 + 88 + DEBUGP("min = %u, range_size = %u\n", min, range_size); 89 + 90 + for (i = 0; i < range_size; i++, key++) { 91 + *keyptr = htonl(min + key % range_size); 92 + if (!ip_nat_used_tuple(tuple, conntrack)) 93 + return 1; 94 + } 95 + 96 + DEBUGP("%p: no NAT mapping\n", conntrack); 97 + 98 + return 0; 99 + } 100 + 101 + /* manipulate a GRE packet according to maniptype */ 102 + static int 103 + gre_manip_pkt(struct sk_buff **pskb, 104 + unsigned int iphdroff, 105 + const struct ip_conntrack_tuple *tuple, 106 + enum ip_nat_manip_type maniptype) 107 + { 108 + struct gre_hdr *greh; 109 + struct gre_hdr_pptp *pgreh; 110 + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); 111 + unsigned int hdroff = iphdroff + iph->ihl*4; 112 + 113 + /* pgreh includes two optional 32bit fields which are not required 114 + * to be there. That's where the magic '8' comes from */ 115 + if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8)) 116 + return 0; 117 + 118 + greh = (void *)(*pskb)->data + hdroff; 119 + pgreh = (struct gre_hdr_pptp *) greh; 120 + 121 + /* we only have destination manip of a packet, since 'source key' 122 + * is not present in the packet itself */ 123 + if (maniptype == IP_NAT_MANIP_DST) { 124 + /* key manipulation is always dest */ 125 + switch (greh->version) { 126 + case 0: 127 + if (!greh->key) { 128 + DEBUGP("can't nat GRE w/o key\n"); 129 + break; 130 + } 131 + if (greh->csum) { 132 + /* FIXME: Never tested this code... */ 133 + *(gre_csum(greh)) = 134 + ip_nat_cheat_check(~*(gre_key(greh)), 135 + tuple->dst.u.gre.key, 136 + *(gre_csum(greh))); 137 + } 138 + *(gre_key(greh)) = tuple->dst.u.gre.key; 139 + break; 140 + case GRE_VERSION_PPTP: 141 + DEBUGP("call_id -> 0x%04x\n", 142 + ntohl(tuple->dst.u.gre.key)); 143 + pgreh->call_id = htons(ntohl(tuple->dst.u.gre.key)); 144 + break; 145 + default: 146 + DEBUGP("can't nat unknown GRE version\n"); 147 + return 0; 148 + break; 149 + } 150 + } 151 + return 1; 152 + } 153 + 154 + /* print out a nat tuple */ 155 + static unsigned int 156 + gre_print(char *buffer, 157 + const struct ip_conntrack_tuple *match, 158 + const struct ip_conntrack_tuple *mask) 159 + { 160 + unsigned int len = 0; 161 + 162 + if (mask->src.u.gre.key) 163 + len += sprintf(buffer + len, "srckey=0x%x ", 164 + ntohl(match->src.u.gre.key)); 165 + 166 + if (mask->dst.u.gre.key) 167 + len += sprintf(buffer + len, "dstkey=0x%x ", 168 + ntohl(match->src.u.gre.key)); 169 + 170 + return len; 171 + } 172 + 173 + /* print a range of keys */ 174 + static unsigned int 175 + gre_print_range(char *buffer, const struct ip_nat_range *range) 176 + { 177 + if (range->min.gre.key != 0 178 + || range->max.gre.key != 0xFFFF) { 179 + if (range->min.gre.key == range->max.gre.key) 180 + return sprintf(buffer, "key 0x%x ", 181 + ntohl(range->min.gre.key)); 182 + else 183 + return sprintf(buffer, "keys 0x%u-0x%u ", 184 + ntohl(range->min.gre.key), 185 + ntohl(range->max.gre.key)); 186 + } else 187 + return 0; 188 + } 189 + 190 + /* nat helper struct */ 191 + static struct ip_nat_protocol gre = { 192 + .name = "GRE", 193 + .protonum = IPPROTO_GRE, 194 + .manip_pkt = gre_manip_pkt, 195 + .in_range = gre_in_range, 196 + .unique_tuple = gre_unique_tuple, 197 + .print = gre_print, 198 + .print_range = gre_print_range, 199 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 200 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 201 + .range_to_nfattr = ip_nat_port_range_to_nfattr, 202 + .nfattr_to_range = ip_nat_port_nfattr_to_range, 203 + #endif 204 + }; 205 + 206 + int __init ip_nat_proto_gre_init(void) 207 + { 208 + return ip_nat_protocol_register(&gre); 209 + } 210 + 211 + void __exit ip_nat_proto_gre_fini(void) 212 + { 213 + ip_nat_protocol_unregister(&gre); 214 + }
+7 -3
net/ipv4/tcp_output.c
··· 461 461 flags = TCP_SKB_CB(skb)->flags; 462 462 TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); 463 463 TCP_SKB_CB(buff)->flags = flags; 464 - TCP_SKB_CB(buff)->sacked = 465 - (TCP_SKB_CB(skb)->sacked & 466 - (TCPCB_LOST | TCPCB_EVER_RETRANS | TCPCB_AT_TAIL)); 464 + TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked; 467 465 TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; 468 466 469 467 if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) { ··· 499 501 tcp_skb_pcount(buff); 500 502 501 503 tp->packets_out -= diff; 504 + 505 + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) 506 + tp->sacked_out -= diff; 507 + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) 508 + tp->retrans_out -= diff; 509 + 502 510 if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { 503 511 tp->lost_out -= diff; 504 512 tp->left_out -= diff;
+52
net/ipv6/netfilter/ip6_tables.c
··· 1955 1955 #endif 1956 1956 } 1957 1957 1958 + /* 1959 + * find specified header up to transport protocol header. 1960 + * If found target header, the offset to the header is set to *offset 1961 + * and return 0. otherwise, return -1. 1962 + * 1963 + * Notes: - non-1st Fragment Header isn't skipped. 1964 + * - ESP header isn't skipped. 1965 + * - The target header may be trancated. 1966 + */ 1967 + int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) 1968 + { 1969 + unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; 1970 + u8 nexthdr = skb->nh.ipv6h->nexthdr; 1971 + unsigned int len = skb->len - start; 1972 + 1973 + while (nexthdr != target) { 1974 + struct ipv6_opt_hdr _hdr, *hp; 1975 + unsigned int hdrlen; 1976 + 1977 + if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) 1978 + return -1; 1979 + hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); 1980 + if (hp == NULL) 1981 + return -1; 1982 + if (nexthdr == NEXTHDR_FRAGMENT) { 1983 + unsigned short _frag_off, *fp; 1984 + fp = skb_header_pointer(skb, 1985 + start+offsetof(struct frag_hdr, 1986 + frag_off), 1987 + sizeof(_frag_off), 1988 + &_frag_off); 1989 + if (fp == NULL) 1990 + return -1; 1991 + 1992 + if (ntohs(*fp) & ~0x7) 1993 + return -1; 1994 + hdrlen = 8; 1995 + } else if (nexthdr == NEXTHDR_AUTH) 1996 + hdrlen = (hp->hdrlen + 2) << 2; 1997 + else 1998 + hdrlen = ipv6_optlen(hp); 1999 + 2000 + nexthdr = hp->nexthdr; 2001 + len -= hdrlen; 2002 + start += hdrlen; 2003 + } 2004 + 2005 + *offset = start; 2006 + return 0; 2007 + } 2008 + 1958 2009 EXPORT_SYMBOL(ip6t_register_table); 1959 2010 EXPORT_SYMBOL(ip6t_unregister_table); 1960 2011 EXPORT_SYMBOL(ip6t_do_table); ··· 2014 1963 EXPORT_SYMBOL(ip6t_register_target); 2015 1964 EXPORT_SYMBOL(ip6t_unregister_target); 2016 1965 EXPORT_SYMBOL(ip6t_ext_hdr); 1966 + EXPORT_SYMBOL(ipv6_find_hdr); 2017 1967 2018 1968 module_init(init); 2019 1969 module_exit(fini);
+5 -76
net/ipv6/netfilter/ip6t_ah.c
··· 48 48 unsigned int protoff, 49 49 int *hotdrop) 50 50 { 51 - struct ip_auth_hdr *ah = NULL, _ah; 51 + struct ip_auth_hdr *ah, _ah; 52 52 const struct ip6t_ah *ahinfo = matchinfo; 53 - unsigned int temp; 54 - int len; 55 - u8 nexthdr; 56 53 unsigned int ptr; 57 54 unsigned int hdrlen = 0; 58 55 59 - /*DEBUGP("IPv6 AH entered\n");*/ 60 - /* if (opt->auth == 0) return 0; 61 - * It does not filled on output */ 62 - 63 - /* type of the 1st exthdr */ 64 - nexthdr = skb->nh.ipv6h->nexthdr; 65 - /* pointer to the 1st exthdr */ 66 - ptr = sizeof(struct ipv6hdr); 67 - /* available length */ 68 - len = skb->len - ptr; 69 - temp = 0; 70 - 71 - while (ip6t_ext_hdr(nexthdr)) { 72 - struct ipv6_opt_hdr _hdr, *hp; 73 - 74 - DEBUGP("ipv6_ah header iteration \n"); 75 - 76 - /* Is there enough space for the next ext header? */ 77 - if (len < sizeof(struct ipv6_opt_hdr)) 78 - return 0; 79 - /* No more exthdr -> evaluate */ 80 - if (nexthdr == NEXTHDR_NONE) 81 - break; 82 - /* ESP -> evaluate */ 83 - if (nexthdr == NEXTHDR_ESP) 84 - break; 85 - 86 - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 87 - BUG_ON(hp == NULL); 88 - 89 - /* Calculate the header length */ 90 - if (nexthdr == NEXTHDR_FRAGMENT) 91 - hdrlen = 8; 92 - else if (nexthdr == NEXTHDR_AUTH) 93 - hdrlen = (hp->hdrlen+2)<<2; 94 - else 95 - hdrlen = ipv6_optlen(hp); 96 - 97 - /* AH -> evaluate */ 98 - if (nexthdr == NEXTHDR_AUTH) { 99 - temp |= MASK_AH; 100 - break; 101 - } 102 - 103 - 104 - /* set the flag */ 105 - switch (nexthdr) { 106 - case NEXTHDR_HOP: 107 - case NEXTHDR_ROUTING: 108 - case NEXTHDR_FRAGMENT: 109 - case NEXTHDR_AUTH: 110 - case NEXTHDR_DEST: 111 - break; 112 - default: 113 - DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr); 114 - return 0; 115 - } 116 - 117 - nexthdr = hp->nexthdr; 118 - len -= hdrlen; 119 - ptr += hdrlen; 120 - if (ptr > skb->len) { 121 - DEBUGP("ipv6_ah: new pointer too large! \n"); 122 - break; 123 - } 124 - } 125 - 126 - /* AH header not found */ 127 - if (temp != MASK_AH) 56 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH) < 0) 128 57 return 0; 129 58 130 - if (len < sizeof(struct ip_auth_hdr)){ 59 + ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); 60 + if (ah == NULL) { 131 61 *hotdrop = 1; 132 62 return 0; 133 63 } 134 64 135 - ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); 136 - BUG_ON(ah == NULL); 65 + hdrlen = (ah->hdrlen + 2) << 2; 137 66 138 67 DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); 139 68 DEBUGP("RES %04X ", ah->reserved);
+7 -81
net/ipv6/netfilter/ip6t_dst.c
··· 63 63 struct ipv6_opt_hdr _optsh, *oh; 64 64 const struct ip6t_opts *optinfo = matchinfo; 65 65 unsigned int temp; 66 - unsigned int len; 67 - u8 nexthdr; 68 66 unsigned int ptr; 69 67 unsigned int hdrlen = 0; 70 68 unsigned int ret = 0; ··· 70 72 u8 _optlen, *lp = NULL; 71 73 unsigned int optlen; 72 74 73 - /* type of the 1st exthdr */ 74 - nexthdr = skb->nh.ipv6h->nexthdr; 75 - /* pointer to the 1st exthdr */ 76 - ptr = sizeof(struct ipv6hdr); 77 - /* available length */ 78 - len = skb->len - ptr; 79 - temp = 0; 80 - 81 - while (ip6t_ext_hdr(nexthdr)) { 82 - struct ipv6_opt_hdr _hdr, *hp; 83 - 84 - DEBUGP("ipv6_opts header iteration \n"); 85 - 86 - /* Is there enough space for the next ext header? */ 87 - if (len < (int)sizeof(struct ipv6_opt_hdr)) 88 - return 0; 89 - /* No more exthdr -> evaluate */ 90 - if (nexthdr == NEXTHDR_NONE) { 91 - break; 92 - } 93 - /* ESP -> evaluate */ 94 - if (nexthdr == NEXTHDR_ESP) { 95 - break; 96 - } 97 - 98 - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 99 - BUG_ON(hp == NULL); 100 - 101 - /* Calculate the header length */ 102 - if (nexthdr == NEXTHDR_FRAGMENT) { 103 - hdrlen = 8; 104 - } else if (nexthdr == NEXTHDR_AUTH) 105 - hdrlen = (hp->hdrlen+2)<<2; 106 - else 107 - hdrlen = ipv6_optlen(hp); 108 - 109 - /* OPTS -> evaluate */ 110 75 #if HOPBYHOP 111 - if (nexthdr == NEXTHDR_HOP) { 112 - temp |= MASK_HOPOPTS; 76 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) 113 77 #else 114 - if (nexthdr == NEXTHDR_DEST) { 115 - temp |= MASK_DSTOPTS; 78 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) 116 79 #endif 117 - break; 118 - } 80 + return 0; 119 81 120 - 121 - /* set the flag */ 122 - switch (nexthdr){ 123 - case NEXTHDR_HOP: 124 - case NEXTHDR_ROUTING: 125 - case NEXTHDR_FRAGMENT: 126 - case NEXTHDR_AUTH: 127 - case NEXTHDR_DEST: 128 - break; 129 - default: 130 - DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); 131 - return 0; 132 - break; 133 - } 134 - 135 - nexthdr = hp->nexthdr; 136 - len -= hdrlen; 137 - ptr += hdrlen; 138 - if ( ptr > skb->len ) { 139 - DEBUGP("ipv6_opts: new pointer is too large! \n"); 140 - break; 141 - } 142 - } 143 - 144 - /* OPTIONS header not found */ 145 - #if HOPBYHOP 146 - if ( temp != MASK_HOPOPTS ) return 0; 147 - #else 148 - if ( temp != MASK_DSTOPTS ) return 0; 149 - #endif 150 - 151 - if (len < (int)sizeof(struct ipv6_opt_hdr)){ 82 + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); 83 + if (oh == NULL){ 152 84 *hotdrop = 1; 153 85 return 0; 154 86 } 155 87 156 - if (len < hdrlen){ 88 + hdrlen = ipv6_optlen(oh); 89 + if (skb->len - ptr < hdrlen){ 157 90 /* Packet smaller than it's length field */ 158 91 return 0; 159 92 } 160 - 161 - oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); 162 - BUG_ON(oh == NULL); 163 93 164 94 DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); 165 95
+4 -69
net/ipv6/netfilter/ip6t_esp.c
··· 48 48 unsigned int protoff, 49 49 int *hotdrop) 50 50 { 51 - struct ip_esp_hdr _esp, *eh = NULL; 51 + struct ip_esp_hdr _esp, *eh; 52 52 const struct ip6t_esp *espinfo = matchinfo; 53 - unsigned int temp; 54 - int len; 55 - u8 nexthdr; 56 53 unsigned int ptr; 57 54 58 55 /* Make sure this isn't an evil packet */ 59 56 /*DEBUGP("ipv6_esp entered \n");*/ 60 57 61 - /* type of the 1st exthdr */ 62 - nexthdr = skb->nh.ipv6h->nexthdr; 63 - /* pointer to the 1st exthdr */ 64 - ptr = sizeof(struct ipv6hdr); 65 - /* available length */ 66 - len = skb->len - ptr; 67 - temp = 0; 68 - 69 - while (ip6t_ext_hdr(nexthdr)) { 70 - struct ipv6_opt_hdr _hdr, *hp; 71 - int hdrlen; 72 - 73 - DEBUGP("ipv6_esp header iteration \n"); 74 - 75 - /* Is there enough space for the next ext header? */ 76 - if (len < sizeof(struct ipv6_opt_hdr)) 77 - return 0; 78 - /* No more exthdr -> evaluate */ 79 - if (nexthdr == NEXTHDR_NONE) 80 - break; 81 - /* ESP -> evaluate */ 82 - if (nexthdr == NEXTHDR_ESP) { 83 - temp |= MASK_ESP; 84 - break; 85 - } 86 - 87 - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 88 - BUG_ON(hp == NULL); 89 - 90 - /* Calculate the header length */ 91 - if (nexthdr == NEXTHDR_FRAGMENT) 92 - hdrlen = 8; 93 - else if (nexthdr == NEXTHDR_AUTH) 94 - hdrlen = (hp->hdrlen+2)<<2; 95 - else 96 - hdrlen = ipv6_optlen(hp); 97 - 98 - /* set the flag */ 99 - switch (nexthdr) { 100 - case NEXTHDR_HOP: 101 - case NEXTHDR_ROUTING: 102 - case NEXTHDR_FRAGMENT: 103 - case NEXTHDR_AUTH: 104 - case NEXTHDR_DEST: 105 - break; 106 - default: 107 - DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr); 108 - return 0; 109 - } 110 - 111 - nexthdr = hp->nexthdr; 112 - len -= hdrlen; 113 - ptr += hdrlen; 114 - if (ptr > skb->len) { 115 - DEBUGP("ipv6_esp: new pointer too large! \n"); 116 - break; 117 - } 118 - } 119 - 120 - /* ESP header not found */ 121 - if (temp != MASK_ESP) 58 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0) 122 59 return 0; 123 60 124 - if (len < sizeof(struct ip_esp_hdr)) { 61 + eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); 62 + if (eh == NULL) { 125 63 *hotdrop = 1; 126 64 return 0; 127 65 } 128 - 129 - eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); 130 - BUG_ON(eh == NULL); 131 66 132 67 DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi)); 133 68
+8 -80
net/ipv6/netfilter/ip6t_frag.c
··· 48 48 unsigned int protoff, 49 49 int *hotdrop) 50 50 { 51 - struct frag_hdr _frag, *fh = NULL; 51 + struct frag_hdr _frag, *fh; 52 52 const struct ip6t_frag *fraginfo = matchinfo; 53 - unsigned int temp; 54 - int len; 55 - u8 nexthdr; 56 53 unsigned int ptr; 57 - unsigned int hdrlen = 0; 58 54 59 - /* type of the 1st exthdr */ 60 - nexthdr = skb->nh.ipv6h->nexthdr; 61 - /* pointer to the 1st exthdr */ 62 - ptr = sizeof(struct ipv6hdr); 63 - /* available length */ 64 - len = skb->len - ptr; 65 - temp = 0; 55 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT) < 0) 56 + return 0; 66 57 67 - while (ip6t_ext_hdr(nexthdr)) { 68 - struct ipv6_opt_hdr _hdr, *hp; 69 - 70 - DEBUGP("ipv6_frag header iteration \n"); 71 - 72 - /* Is there enough space for the next ext header? */ 73 - if (len < (int)sizeof(struct ipv6_opt_hdr)) 74 - return 0; 75 - /* No more exthdr -> evaluate */ 76 - if (nexthdr == NEXTHDR_NONE) { 77 - break; 78 - } 79 - /* ESP -> evaluate */ 80 - if (nexthdr == NEXTHDR_ESP) { 81 - break; 82 - } 83 - 84 - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 85 - BUG_ON(hp == NULL); 86 - 87 - /* Calculate the header length */ 88 - if (nexthdr == NEXTHDR_FRAGMENT) { 89 - hdrlen = 8; 90 - } else if (nexthdr == NEXTHDR_AUTH) 91 - hdrlen = (hp->hdrlen+2)<<2; 92 - else 93 - hdrlen = ipv6_optlen(hp); 94 - 95 - /* FRAG -> evaluate */ 96 - if (nexthdr == NEXTHDR_FRAGMENT) { 97 - temp |= MASK_FRAGMENT; 98 - break; 99 - } 100 - 101 - 102 - /* set the flag */ 103 - switch (nexthdr){ 104 - case NEXTHDR_HOP: 105 - case NEXTHDR_ROUTING: 106 - case NEXTHDR_FRAGMENT: 107 - case NEXTHDR_AUTH: 108 - case NEXTHDR_DEST: 109 - break; 110 - default: 111 - DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr); 112 - return 0; 113 - break; 114 - } 115 - 116 - nexthdr = hp->nexthdr; 117 - len -= hdrlen; 118 - ptr += hdrlen; 119 - if ( ptr > skb->len ) { 120 - DEBUGP("ipv6_frag: new pointer too large! \n"); 121 - break; 122 - } 123 - } 124 - 125 - /* FRAG header not found */ 126 - if ( temp != MASK_FRAGMENT ) return 0; 127 - 128 - if (len < sizeof(struct frag_hdr)){ 129 - *hotdrop = 1; 130 - return 0; 131 - } 132 - 133 - fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); 134 - BUG_ON(fh == NULL); 58 + fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); 59 + if (fh == NULL){ 60 + *hotdrop = 1; 61 + return 0; 62 + } 135 63 136 64 DEBUGP("INFO %04X ", fh->frag_off); 137 65 DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
+7 -81
net/ipv6/netfilter/ip6t_hbh.c
··· 63 63 struct ipv6_opt_hdr _optsh, *oh; 64 64 const struct ip6t_opts *optinfo = matchinfo; 65 65 unsigned int temp; 66 - unsigned int len; 67 - u8 nexthdr; 68 66 unsigned int ptr; 69 67 unsigned int hdrlen = 0; 70 68 unsigned int ret = 0; ··· 70 72 u8 _optlen, *lp = NULL; 71 73 unsigned int optlen; 72 74 73 - /* type of the 1st exthdr */ 74 - nexthdr = skb->nh.ipv6h->nexthdr; 75 - /* pointer to the 1st exthdr */ 76 - ptr = sizeof(struct ipv6hdr); 77 - /* available length */ 78 - len = skb->len - ptr; 79 - temp = 0; 80 - 81 - while (ip6t_ext_hdr(nexthdr)) { 82 - struct ipv6_opt_hdr _hdr, *hp; 83 - 84 - DEBUGP("ipv6_opts header iteration \n"); 85 - 86 - /* Is there enough space for the next ext header? */ 87 - if (len < (int)sizeof(struct ipv6_opt_hdr)) 88 - return 0; 89 - /* No more exthdr -> evaluate */ 90 - if (nexthdr == NEXTHDR_NONE) { 91 - break; 92 - } 93 - /* ESP -> evaluate */ 94 - if (nexthdr == NEXTHDR_ESP) { 95 - break; 96 - } 97 - 98 - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 99 - BUG_ON(hp == NULL); 100 - 101 - /* Calculate the header length */ 102 - if (nexthdr == NEXTHDR_FRAGMENT) { 103 - hdrlen = 8; 104 - } else if (nexthdr == NEXTHDR_AUTH) 105 - hdrlen = (hp->hdrlen+2)<<2; 106 - else 107 - hdrlen = ipv6_optlen(hp); 108 - 109 - /* OPTS -> evaluate */ 110 75 #if HOPBYHOP 111 - if (nexthdr == NEXTHDR_HOP) { 112 - temp |= MASK_HOPOPTS; 76 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) 113 77 #else 114 - if (nexthdr == NEXTHDR_DEST) { 115 - temp |= MASK_DSTOPTS; 78 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) 116 79 #endif 117 - break; 118 - } 80 + return 0; 119 81 120 - 121 - /* set the flag */ 122 - switch (nexthdr){ 123 - case NEXTHDR_HOP: 124 - case NEXTHDR_ROUTING: 125 - case NEXTHDR_FRAGMENT: 126 - case NEXTHDR_AUTH: 127 - case NEXTHDR_DEST: 128 - break; 129 - default: 130 - DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); 131 - return 0; 132 - break; 133 - } 134 - 135 - nexthdr = hp->nexthdr; 136 - len -= hdrlen; 137 - ptr += hdrlen; 138 - if ( ptr > skb->len ) { 139 - DEBUGP("ipv6_opts: new pointer is too large! \n"); 140 - break; 141 - } 142 - } 143 - 144 - /* OPTIONS header not found */ 145 - #if HOPBYHOP 146 - if ( temp != MASK_HOPOPTS ) return 0; 147 - #else 148 - if ( temp != MASK_DSTOPTS ) return 0; 149 - #endif 150 - 151 - if (len < (int)sizeof(struct ipv6_opt_hdr)){ 82 + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); 83 + if (oh == NULL){ 152 84 *hotdrop = 1; 153 85 return 0; 154 86 } 155 87 156 - if (len < hdrlen){ 88 + hdrlen = ipv6_optlen(oh); 89 + if (skb->len - ptr < hdrlen){ 157 90 /* Packet smaller than it's length field */ 158 91 return 0; 159 92 } 160 - 161 - oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); 162 - BUG_ON(oh == NULL); 163 93 164 94 DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); 165 95
+7 -76
net/ipv6/netfilter/ip6t_rt.c
··· 50 50 unsigned int protoff, 51 51 int *hotdrop) 52 52 { 53 - struct ipv6_rt_hdr _route, *rh = NULL; 53 + struct ipv6_rt_hdr _route, *rh; 54 54 const struct ip6t_rt *rtinfo = matchinfo; 55 55 unsigned int temp; 56 - unsigned int len; 57 - u8 nexthdr; 58 56 unsigned int ptr; 59 57 unsigned int hdrlen = 0; 60 58 unsigned int ret = 0; 61 59 struct in6_addr *ap, _addr; 62 60 63 - /* type of the 1st exthdr */ 64 - nexthdr = skb->nh.ipv6h->nexthdr; 65 - /* pointer to the 1st exthdr */ 66 - ptr = sizeof(struct ipv6hdr); 67 - /* available length */ 68 - len = skb->len - ptr; 69 - temp = 0; 61 + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING) < 0) 62 + return 0; 70 63 71 - while (ip6t_ext_hdr(nexthdr)) { 72 - struct ipv6_opt_hdr _hdr, *hp; 73 - 74 - DEBUGP("ipv6_rt header iteration \n"); 75 - 76 - /* Is there enough space for the next ext header? */ 77 - if (len < (int)sizeof(struct ipv6_opt_hdr)) 78 - return 0; 79 - /* No more exthdr -> evaluate */ 80 - if (nexthdr == NEXTHDR_NONE) { 81 - break; 82 - } 83 - /* ESP -> evaluate */ 84 - if (nexthdr == NEXTHDR_ESP) { 85 - break; 86 - } 87 - 88 - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 89 - BUG_ON(hp == NULL); 90 - 91 - /* Calculate the header length */ 92 - if (nexthdr == NEXTHDR_FRAGMENT) { 93 - hdrlen = 8; 94 - } else if (nexthdr == NEXTHDR_AUTH) 95 - hdrlen = (hp->hdrlen+2)<<2; 96 - else 97 - hdrlen = ipv6_optlen(hp); 98 - 99 - /* ROUTING -> evaluate */ 100 - if (nexthdr == NEXTHDR_ROUTING) { 101 - temp |= MASK_ROUTING; 102 - break; 103 - } 104 - 105 - 106 - /* set the flag */ 107 - switch (nexthdr){ 108 - case NEXTHDR_HOP: 109 - case NEXTHDR_ROUTING: 110 - case NEXTHDR_FRAGMENT: 111 - case NEXTHDR_AUTH: 112 - case NEXTHDR_DEST: 113 - break; 114 - default: 115 - DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr); 116 - return 0; 117 - break; 118 - } 119 - 120 - nexthdr = hp->nexthdr; 121 - len -= hdrlen; 122 - ptr += hdrlen; 123 - if ( ptr > skb->len ) { 124 - DEBUGP("ipv6_rt: new pointer is too large! \n"); 125 - break; 126 - } 127 - } 128 - 129 - /* ROUTING header not found */ 130 - if ( temp != MASK_ROUTING ) return 0; 131 - 132 - if (len < (int)sizeof(struct ipv6_rt_hdr)){ 64 + rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); 65 + if (rh == NULL){ 133 66 *hotdrop = 1; 134 67 return 0; 135 68 } 136 69 137 - if (len < hdrlen){ 70 + hdrlen = ipv6_optlen(rh); 71 + if (skb->len - ptr < hdrlen){ 138 72 /* Pcket smaller than its length field */ 139 73 return 0; 140 74 } 141 - 142 - rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); 143 - BUG_ON(rh == NULL); 144 75 145 76 DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen); 146 77 DEBUGP("TYPE %04X ", rh->type);