diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-19 21:46:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-19 21:46:11 -0400 |
| commit | 875bd5ab01bc0b760fd4e97838931cd2e7456cbd (patch) | |
| tree | b921bc8feb0e0d6f2537987cd820429b15804a87 | |
| parent | 6d1cfe3f1752f17e297df60c8bcc6cd6e0a58449 (diff) | |
| parent | e14c3caf605dfd29bd1aac3097e39db94afc9f07 (diff) | |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
28 files changed, 2382 insertions, 496 deletions
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 48c03c11cd9a..a01efa6d5c62 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c | |||
| @@ -72,7 +72,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, | |||
| 72 | } | 72 | } |
| 73 | skb_reserve(skb, 4); | 73 | skb_reserve(skb, 4); |
| 74 | cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); | 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 | data->type = htonl(type); | 77 | data->type = htonl(type); |
| 78 | data->par1 = htonl(par1); | 78 | data->par1 = htonl(par1); |
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 17d0c0d40b0e..eef0876d8307 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h | |||
| @@ -42,8 +42,8 @@ struct hlist_node; | |||
| 42 | struct vlan_ethhdr { | 42 | struct vlan_ethhdr { |
| 43 | unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ | 43 | unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ |
| 44 | unsigned char h_source[ETH_ALEN]; /* source ether addr */ | 44 | unsigned char h_source[ETH_ALEN]; /* source ether addr */ |
| 45 | unsigned short h_vlan_proto; /* Should always be 0x8100 */ | 45 | __be16 h_vlan_proto; /* Should always be 0x8100 */ |
| 46 | unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ | 46 | __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */ |
| 47 | unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ | 47 | unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| @@ -55,8 +55,8 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb) | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | struct vlan_hdr { | 57 | struct vlan_hdr { |
| 58 | unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ | 58 | __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */ |
| 59 | unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ | 59 | __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */ |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | #define VLAN_VID_MASK 0xfff | 62 | #define VLAN_VID_MASK 0xfff |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 7e033e9271a8..bace72a76cc4 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h | |||
| @@ -133,11 +133,13 @@ enum ip_conntrack_expect_events { | |||
| 133 | 133 | ||
| 134 | #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> | 134 | #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> |
| 135 | #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> | 135 | #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> |
| 136 | #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> | ||
| 136 | #include <linux/netfilter_ipv4/ip_conntrack_sctp.h> | 137 | #include <linux/netfilter_ipv4/ip_conntrack_sctp.h> |
| 137 | 138 | ||
| 138 | /* per conntrack: protocol private data */ | 139 | /* per conntrack: protocol private data */ |
| 139 | union ip_conntrack_proto { | 140 | union ip_conntrack_proto { |
| 140 | /* insert conntrack proto private data here */ | 141 | /* insert conntrack proto private data here */ |
| 142 | struct ip_ct_gre gre; | ||
| 141 | struct ip_ct_sctp sctp; | 143 | struct ip_ct_sctp sctp; |
| 142 | struct ip_ct_tcp tcp; | 144 | struct ip_ct_tcp tcp; |
| 143 | struct ip_ct_icmp icmp; | 145 | struct ip_ct_icmp icmp; |
| @@ -148,6 +150,7 @@ union ip_conntrack_expect_proto { | |||
| 148 | }; | 150 | }; |
| 149 | 151 | ||
| 150 | /* Add protocol helper include file here */ | 152 | /* Add protocol helper include file here */ |
| 153 | #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> | ||
| 151 | #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> | 154 | #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> |
| 152 | #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> | 155 | #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> |
| 153 | #include <linux/netfilter_ipv4/ip_conntrack_irc.h> | 156 | #include <linux/netfilter_ipv4/ip_conntrack_irc.h> |
| @@ -155,12 +158,20 @@ union ip_conntrack_expect_proto { | |||
| 155 | /* per conntrack: application helper private data */ | 158 | /* per conntrack: application helper private data */ |
| 156 | union ip_conntrack_help { | 159 | union ip_conntrack_help { |
| 157 | /* insert conntrack helper private data (master) here */ | 160 | /* insert conntrack helper private data (master) here */ |
| 161 | struct ip_ct_pptp_master ct_pptp_info; | ||
| 158 | struct ip_ct_ftp_master ct_ftp_info; | 162 | struct ip_ct_ftp_master ct_ftp_info; |
| 159 | struct ip_ct_irc_master ct_irc_info; | 163 | struct ip_ct_irc_master ct_irc_info; |
| 160 | }; | 164 | }; |
| 161 | 165 | ||
| 162 | #ifdef CONFIG_IP_NF_NAT_NEEDED | 166 | #ifdef CONFIG_IP_NF_NAT_NEEDED |
| 163 | #include <linux/netfilter_ipv4/ip_nat.h> | 167 | #include <linux/netfilter_ipv4/ip_nat.h> |
| 168 | #include <linux/netfilter_ipv4/ip_nat_pptp.h> | ||
| 169 | |||
| 170 | /* per conntrack: nat application helper private data */ | ||
| 171 | union ip_conntrack_nat_help { | ||
| 172 | /* insert nat helper private data here */ | ||
| 173 | struct ip_nat_pptp nat_pptp_info; | ||
| 174 | }; | ||
| 164 | #endif | 175 | #endif |
| 165 | 176 | ||
| 166 | #include <linux/types.h> | 177 | #include <linux/types.h> |
| @@ -223,6 +234,7 @@ struct ip_conntrack | |||
| 223 | #ifdef CONFIG_IP_NF_NAT_NEEDED | 234 | #ifdef CONFIG_IP_NF_NAT_NEEDED |
| 224 | struct { | 235 | struct { |
| 225 | struct ip_nat_info info; | 236 | struct ip_nat_info info; |
| 237 | union ip_conntrack_nat_help help; | ||
| 226 | #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ | 238 | #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ |
| 227 | defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) | 239 | defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) |
| 228 | int masq_index; | 240 | int masq_index; |
| @@ -372,7 +384,7 @@ extern struct ip_conntrack_expect * | |||
| 372 | __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); | 384 | __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); |
| 373 | 385 | ||
| 374 | extern struct ip_conntrack_expect * | 386 | extern struct ip_conntrack_expect * |
| 375 | ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); | 387 | ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); |
| 376 | 388 | ||
| 377 | extern struct ip_conntrack_tuple_hash * | 389 | extern struct ip_conntrack_tuple_hash * |
| 378 | __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, | 390 | __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h new file mode 100644 index 000000000000..389e3851d52f --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h | |||
| @@ -0,0 +1,332 @@ | |||
| 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 */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h new file mode 100644 index 000000000000..8d090ef82f5f --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h | |||
| @@ -0,0 +1,114 @@ | |||
| 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 */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h index c33f0b5e0d0a..14dc0f7b6556 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h | |||
| @@ -28,6 +28,9 @@ union ip_conntrack_manip_proto | |||
| 28 | struct { | 28 | struct { |
| 29 | u_int16_t port; | 29 | u_int16_t port; |
| 30 | } sctp; | 30 | } sctp; |
| 31 | struct { | ||
| 32 | u_int16_t key; /* key is 32bit, pptp only uses 16 */ | ||
| 33 | } gre; | ||
| 31 | }; | 34 | }; |
| 32 | 35 | ||
| 33 | /* The manipulable part of the tuple. */ | 36 | /* The manipulable part of the tuple. */ |
| @@ -61,6 +64,10 @@ struct ip_conntrack_tuple | |||
| 61 | struct { | 64 | struct { |
| 62 | u_int16_t port; | 65 | u_int16_t port; |
| 63 | } sctp; | 66 | } sctp; |
| 67 | struct { | ||
| 68 | u_int16_t key; /* key is 32bit, | ||
| 69 | * pptp only uses 16 */ | ||
| 70 | } gre; | ||
| 64 | } u; | 71 | } u; |
| 65 | 72 | ||
| 66 | /* The protocol. */ | 73 | /* The protocol. */ |
diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h new file mode 100644 index 000000000000..eaf66c2e8f93 --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_nat_pptp.h | |||
| @@ -0,0 +1,11 @@ | |||
| 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 */ | ||
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 58c72a52dc65..59f70b34e029 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
| @@ -455,6 +455,9 @@ extern unsigned int ip6t_do_table(struct sk_buff **pskb, | |||
| 455 | 455 | ||
| 456 | /* Check for an extension */ | 456 | /* Check for an extension */ |
| 457 | extern int ip6t_ext_hdr(u8 nexthdr); | 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 | #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) | 462 | #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) |
| 460 | 463 | ||
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 145f5cde96cf..b74864889670 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
| @@ -120,7 +120,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
| 120 | unsigned short vid; | 120 | unsigned short vid; |
| 121 | struct net_device_stats *stats; | 121 | struct net_device_stats *stats; |
| 122 | unsigned short vlan_TCI; | 122 | unsigned short vlan_TCI; |
| 123 | unsigned short proto; | 123 | __be16 proto; |
| 124 | 124 | ||
| 125 | /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */ | 125 | /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */ |
| 126 | vlan_TCI = ntohs(vhdr->h_vlan_TCI); | 126 | vlan_TCI = ntohs(vhdr->h_vlan_TCI); |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 1b63b4824164..90ae70870a10 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
| @@ -43,7 +43,7 @@ | |||
| 43 | * 2 of the License, or (at your option) any later version. | 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 | #include <linux/config.h> | 48 | #include <linux/config.h> |
| 49 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
| @@ -224,7 +224,7 @@ static inline int tkey_mismatch(t_key a, int offset, t_key b) | |||
| 224 | Consider a node 'n' and its parent 'tp'. | 224 | Consider a node 'n' and its parent 'tp'. |
| 225 | 225 | ||
| 226 | If n is a leaf, every bit in its key is significant. Its presence is | 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 | searching for a leaf - unless we are doing an insertion) we will completely | 228 | searching for a leaf - unless we are doing an insertion) we will completely |
| 229 | ignore all skipped bits we encounter. Thus we need to verify, at the end of | 229 | ignore all skipped bits we encounter. Thus we need to verify, at the end of |
| 230 | a potentially successful search, that we have indeed been walking the | 230 | a potentially successful search, that we have indeed been walking the |
| @@ -836,11 +836,12 @@ static void trie_init(struct trie *t) | |||
| 836 | #endif | 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 | via get_fa_head and dump */ | 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 | struct hlist_node *node; | 845 | struct hlist_node *node; |
| 845 | struct leaf_info *li; | 846 | struct leaf_info *li; |
| 846 | 847 | ||
| @@ -853,7 +854,7 @@ static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen) | |||
| 853 | 854 | ||
| 854 | static inline struct list_head * get_fa_head(struct leaf *l, int plen) | 855 | static inline struct list_head * get_fa_head(struct leaf *l, int plen) |
| 855 | { | 856 | { |
| 856 | struct leaf_info *li = find_leaf_info(&l->list, plen); | 857 | struct leaf_info *li = find_leaf_info(l, plen); |
| 857 | 858 | ||
| 858 | if (!li) | 859 | if (!li) |
| 859 | return NULL; | 860 | return NULL; |
| @@ -1248,7 +1249,7 @@ err: | |||
| 1248 | } | 1249 | } |
| 1249 | 1250 | ||
| 1250 | 1251 | ||
| 1251 | /* should be clalled with rcu_read_lock */ | 1252 | /* should be called with rcu_read_lock */ |
| 1252 | static inline int check_leaf(struct trie *t, struct leaf *l, | 1253 | static inline int check_leaf(struct trie *t, struct leaf *l, |
| 1253 | t_key key, int *plen, const struct flowi *flp, | 1254 | t_key key, int *plen, const struct flowi *flp, |
| 1254 | struct fib_result *res) | 1255 | struct fib_result *res) |
| @@ -1590,7 +1591,7 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
| 1590 | rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req); | 1591 | rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req); |
| 1591 | 1592 | ||
| 1592 | l = fib_find_node(t, key); | 1593 | l = fib_find_node(t, key); |
| 1593 | li = find_leaf_info(&l->list, plen); | 1594 | li = find_leaf_info(l, plen); |
| 1594 | 1595 | ||
| 1595 | list_del_rcu(&fa->fa_list); | 1596 | list_del_rcu(&fa->fa_list); |
| 1596 | 1597 | ||
| @@ -1714,7 +1715,6 @@ static int fn_trie_flush(struct fib_table *tb) | |||
| 1714 | 1715 | ||
| 1715 | t->revision++; | 1716 | t->revision++; |
| 1716 | 1717 | ||
| 1717 | rcu_read_lock(); | ||
| 1718 | for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { | 1718 | for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { |
| 1719 | found += trie_flush_leaf(t, l); | 1719 | found += trie_flush_leaf(t, l); |
| 1720 | 1720 | ||
| @@ -1722,7 +1722,6 @@ static int fn_trie_flush(struct fib_table *tb) | |||
| 1722 | trie_leaf_remove(t, ll->key); | 1722 | trie_leaf_remove(t, ll->key); |
| 1723 | ll = l; | 1723 | ll = l; |
| 1724 | } | 1724 | } |
| 1725 | rcu_read_unlock(); | ||
| 1726 | 1725 | ||
| 1727 | if (ll && hlist_empty(&ll->list)) | 1726 | if (ll && hlist_empty(&ll->list)) |
| 1728 | trie_leaf_remove(t, ll->key); | 1727 | trie_leaf_remove(t, ll->key); |
| @@ -2029,7 +2028,7 @@ static struct node *fib_trie_get_first(struct fib_trie_iter *iter, | |||
| 2029 | iter->tnode = (struct tnode *) n; | 2028 | iter->tnode = (struct tnode *) n; |
| 2030 | iter->trie = t; | 2029 | iter->trie = t; |
| 2031 | iter->index = 0; | 2030 | iter->index = 0; |
| 2032 | iter->depth = 0; | 2031 | iter->depth = 1; |
| 2033 | return n; | 2032 | return n; |
| 2034 | } | 2033 | } |
| 2035 | return NULL; | 2034 | return NULL; |
| @@ -2274,11 +2273,12 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) | |||
| 2274 | seq_puts(seq, "<local>:\n"); | 2273 | seq_puts(seq, "<local>:\n"); |
| 2275 | else | 2274 | else |
| 2276 | seq_puts(seq, "<main>:\n"); | 2275 | seq_puts(seq, "<main>:\n"); |
| 2277 | } else { | 2276 | } |
| 2278 | seq_indent(seq, iter->depth-1); | 2277 | seq_indent(seq, iter->depth-1); |
| 2279 | seq_printf(seq, " +-- %d.%d.%d.%d/%d\n", | 2278 | seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n", |
| 2280 | NIPQUAD(prf), tn->pos); | 2279 | NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, |
| 2281 | } | 2280 | tn->empty_children); |
| 2281 | |||
| 2282 | } else { | 2282 | } else { |
| 2283 | struct leaf *l = (struct leaf *) n; | 2283 | struct leaf *l = (struct leaf *) n; |
| 2284 | int i; | 2284 | int i; |
| @@ -2287,7 +2287,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) | |||
| 2287 | seq_indent(seq, iter->depth); | 2287 | seq_indent(seq, iter->depth); |
| 2288 | seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); | 2288 | seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); |
| 2289 | for (i = 32; i >= 0; i--) { | 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 | if (li) { | 2291 | if (li) { |
| 2292 | struct fib_alias *fa; | 2292 | struct fib_alias *fa; |
| 2293 | list_for_each_entry_rcu(fa, &li->falh, fa_list) { | 2293 | list_for_each_entry_rcu(fa, &li->falh, fa_list) { |
| @@ -2383,7 +2383,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) | |||
| 2383 | return 0; | 2383 | return 0; |
| 2384 | 2384 | ||
| 2385 | for (i=32; i>=0; i--) { | 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 | struct fib_alias *fa; | 2387 | struct fib_alias *fa; |
| 2388 | u32 mask, prefix; | 2388 | u32 mask, prefix; |
| 2389 | 2389 | ||
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index e2162d270073..3cf9b451675c 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
| @@ -137,6 +137,22 @@ config IP_NF_AMANDA | |||
| 137 | 137 | ||
| 138 | To compile it as a module, choose M here. If unsure, say Y. | 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 | config IP_NF_QUEUE | 156 | config IP_NF_QUEUE |
| 141 | tristate "IP Userspace queueing via NETLINK (OBSOLETE)" | 157 | tristate "IP Userspace queueing via NETLINK (OBSOLETE)" |
| 142 | help | 158 | help |
| @@ -621,6 +637,12 @@ config IP_NF_NAT_AMANDA | |||
| 621 | default IP_NF_NAT if IP_NF_AMANDA=y | 637 | default IP_NF_NAT if IP_NF_AMANDA=y |
| 622 | default m if IP_NF_AMANDA=m | 638 | default m if IP_NF_AMANDA=m |
| 623 | 639 | ||
| 640 | config IP_NF_NAT_PPTP | ||
| 641 | tristate | ||
| 642 | depends on IP_NF_NAT!=n && IP_NF_PPTP!=n | ||
| 643 | default IP_NF_NAT if IP_NF_PPTP=y | ||
| 644 | default m if IP_NF_PPTP=m | ||
| 645 | |||
| 624 | # mangle + specific targets | 646 | # mangle + specific targets |
| 625 | config IP_NF_MANGLE | 647 | config IP_NF_MANGLE |
| 626 | tristate "Packet mangling" | 648 | tristate "Packet mangling" |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 1ba0db746817..3d45d3c0283c 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
| @@ -6,6 +6,9 @@ | |||
| 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 | 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 | 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 | 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 | # connection tracking | 12 | # connection tracking |
| 10 | obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o | 13 | obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o |
| 11 | 14 | ||
| @@ -17,6 +20,7 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o | |||
| 17 | obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o | 20 | obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o |
| 18 | 21 | ||
| 19 | # connection tracking helpers | 22 | # connection tracking helpers |
| 23 | obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o | ||
| 20 | obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o | 24 | obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o |
| 21 | obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o | 25 | obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o |
| 22 | obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o | 26 | obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o |
| @@ -24,6 +28,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o | |||
| 24 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o | 28 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o |
| 25 | 29 | ||
| 26 | # NAT helpers | 30 | # NAT helpers |
| 31 | obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o | ||
| 27 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o | 32 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o |
| 28 | obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o | 33 | obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o |
| 29 | obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o | 34 | obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o |
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index f8cd8e42961e..c1f82e0c81cf 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
| @@ -233,7 +233,7 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) | |||
| 233 | 233 | ||
| 234 | /* Just find a expectation corresponding to a tuple. */ | 234 | /* Just find a expectation corresponding to a tuple. */ |
| 235 | struct ip_conntrack_expect * | 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 | struct ip_conntrack_expect *i; | 238 | struct ip_conntrack_expect *i; |
| 239 | 239 | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c new file mode 100644 index 000000000000..79db5b70d5f6 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c | |||
| @@ -0,0 +1,805 @@ | |||
| 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); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 15aef3564742..b08a432efcf8 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
| @@ -1270,7 +1270,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | |||
| 1270 | if (err < 0) | 1270 | if (err < 0) |
| 1271 | return err; | 1271 | return err; |
| 1272 | 1272 | ||
| 1273 | exp = ip_conntrack_expect_find_get(&tuple); | 1273 | exp = ip_conntrack_expect_find(&tuple); |
| 1274 | if (!exp) | 1274 | if (!exp) |
| 1275 | return -ENOENT; | 1275 | return -ENOENT; |
| 1276 | 1276 | ||
| @@ -1318,7 +1318,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | |||
| 1318 | return err; | 1318 | return err; |
| 1319 | 1319 | ||
| 1320 | /* bump usage count to 2 */ | 1320 | /* bump usage count to 2 */ |
| 1321 | exp = ip_conntrack_expect_find_get(&tuple); | 1321 | exp = ip_conntrack_expect_find(&tuple); |
| 1322 | if (!exp) | 1322 | if (!exp) |
| 1323 | return -ENOENT; | 1323 | return -ENOENT; |
| 1324 | 1324 | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c new file mode 100644 index 000000000000..de3cb9db6f85 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c | |||
| @@ -0,0 +1,327 @@ | |||
| 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); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index ae3e3e655db5..d3c7808010ec 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c | |||
| @@ -993,11 +993,11 @@ EXPORT_SYMBOL(ip_ct_refresh_acct); | |||
| 993 | 993 | ||
| 994 | EXPORT_SYMBOL(ip_conntrack_expect_alloc); | 994 | EXPORT_SYMBOL(ip_conntrack_expect_alloc); |
| 995 | EXPORT_SYMBOL(ip_conntrack_expect_put); | 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 | EXPORT_SYMBOL(ip_conntrack_expect_related); | 998 | EXPORT_SYMBOL(ip_conntrack_expect_related); |
| 998 | EXPORT_SYMBOL(ip_conntrack_unexpect_related); | 999 | EXPORT_SYMBOL(ip_conntrack_unexpect_related); |
| 999 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); | 1000 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); |
| 1000 | EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); | ||
| 1001 | EXPORT_SYMBOL_GPL(ip_ct_unlink_expect); | 1001 | EXPORT_SYMBOL_GPL(ip_ct_unlink_expect); |
| 1002 | 1002 | ||
| 1003 | EXPORT_SYMBOL(ip_conntrack_tuple_taken); | 1003 | EXPORT_SYMBOL(ip_conntrack_tuple_taken); |
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 1adedb743f60..c3ea891d38e7 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c | |||
| @@ -578,6 +578,8 @@ ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range) | |||
| 578 | 578 | ||
| 579 | return ret; | 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 | #endif | 583 | #endif |
| 582 | 584 | ||
| 583 | int __init ip_nat_init(void) | 585 | int __init ip_nat_init(void) |
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c new file mode 100644 index 000000000000..3cdd0684d30d --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c | |||
| @@ -0,0 +1,401 @@ | |||
| 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); | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c new file mode 100644 index 000000000000..7c1285401672 --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c | |||
| @@ -0,0 +1,214 @@ | |||
| 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 | } | ||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b018e31b6530..5dd6dd7d091e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -461,9 +461,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss | |||
| 461 | flags = TCP_SKB_CB(skb)->flags; | 461 | flags = TCP_SKB_CB(skb)->flags; |
| 462 | TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); | 462 | TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); |
| 463 | TCP_SKB_CB(buff)->flags = flags; | 463 | TCP_SKB_CB(buff)->flags = flags; |
| 464 | TCP_SKB_CB(buff)->sacked = | 464 | TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked; |
| 465 | (TCP_SKB_CB(skb)->sacked & | ||
| 466 | (TCPCB_LOST | TCPCB_EVER_RETRANS | TCPCB_AT_TAIL)); | ||
| 467 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; | 465 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; |
| 468 | 466 | ||
| 469 | if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) { | 467 | if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) { |
| @@ -501,6 +499,12 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss | |||
| 501 | tcp_skb_pcount(buff); | 499 | tcp_skb_pcount(buff); |
| 502 | 500 | ||
| 503 | tp->packets_out -= diff; | 501 | tp->packets_out -= diff; |
| 502 | |||
| 503 | if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) | ||
| 504 | tp->sacked_out -= diff; | ||
| 505 | if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) | ||
| 506 | tp->retrans_out -= diff; | ||
| 507 | |||
| 504 | if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { | 508 | if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { |
| 505 | tp->lost_out -= diff; | 509 | tp->lost_out -= diff; |
| 506 | tp->left_out -= diff; | 510 | tp->left_out -= diff; |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 1cb8adb2787f..2da514b16d95 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -1955,6 +1955,57 @@ static void __exit fini(void) | |||
| 1955 | #endif | 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 | EXPORT_SYMBOL(ip6t_register_table); | 2009 | EXPORT_SYMBOL(ip6t_register_table); |
| 1959 | EXPORT_SYMBOL(ip6t_unregister_table); | 2010 | EXPORT_SYMBOL(ip6t_unregister_table); |
| 1960 | EXPORT_SYMBOL(ip6t_do_table); | 2011 | EXPORT_SYMBOL(ip6t_do_table); |
| @@ -1963,6 +2014,7 @@ EXPORT_SYMBOL(ip6t_unregister_match); | |||
| 1963 | EXPORT_SYMBOL(ip6t_register_target); | 2014 | EXPORT_SYMBOL(ip6t_register_target); |
| 1964 | EXPORT_SYMBOL(ip6t_unregister_target); | 2015 | EXPORT_SYMBOL(ip6t_unregister_target); |
| 1965 | EXPORT_SYMBOL(ip6t_ext_hdr); | 2016 | EXPORT_SYMBOL(ip6t_ext_hdr); |
| 2017 | EXPORT_SYMBOL(ipv6_find_hdr); | ||
| 1966 | 2018 | ||
| 1967 | module_init(init); | 2019 | module_init(init); |
| 1968 | module_exit(fini); | 2020 | module_exit(fini); |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index d5b94f142bba..dde37793d20b 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
| @@ -48,92 +48,21 @@ match(const struct sk_buff *skb, | |||
| 48 | unsigned int protoff, | 48 | unsigned int protoff, |
| 49 | int *hotdrop) | 49 | int *hotdrop) |
| 50 | { | 50 | { |
| 51 | struct ip_auth_hdr *ah = NULL, _ah; | 51 | struct ip_auth_hdr *ah, _ah; |
| 52 | const struct ip6t_ah *ahinfo = matchinfo; | 52 | const struct ip6t_ah *ahinfo = matchinfo; |
| 53 | unsigned int temp; | ||
| 54 | int len; | ||
| 55 | u8 nexthdr; | ||
| 56 | unsigned int ptr; | 53 | unsigned int ptr; |
| 57 | unsigned int hdrlen = 0; | 54 | unsigned int hdrlen = 0; |
| 58 | 55 | ||
| 59 | /*DEBUGP("IPv6 AH entered\n");*/ | 56 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH) < 0) |
| 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) | ||
| 128 | return 0; | 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 | *hotdrop = 1; | 61 | *hotdrop = 1; |
| 132 | return 0; | 62 | return 0; |
| 133 | } | 63 | } |
| 134 | 64 | ||
| 135 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); | 65 | hdrlen = (ah->hdrlen + 2) << 2; |
| 136 | BUG_ON(ah == NULL); | ||
| 137 | 66 | ||
| 138 | DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); | 67 | DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); |
| 139 | DEBUGP("RES %04X ", ah->reserved); | 68 | DEBUGP("RES %04X ", ah->reserved); |
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index 540925e4a7a8..c450a635e54b 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c | |||
| @@ -63,8 +63,6 @@ match(const struct sk_buff *skb, | |||
| 63 | struct ipv6_opt_hdr _optsh, *oh; | 63 | struct ipv6_opt_hdr _optsh, *oh; |
| 64 | const struct ip6t_opts *optinfo = matchinfo; | 64 | const struct ip6t_opts *optinfo = matchinfo; |
| 65 | unsigned int temp; | 65 | unsigned int temp; |
| 66 | unsigned int len; | ||
| 67 | u8 nexthdr; | ||
| 68 | unsigned int ptr; | 66 | unsigned int ptr; |
| 69 | unsigned int hdrlen = 0; | 67 | unsigned int hdrlen = 0; |
| 70 | unsigned int ret = 0; | 68 | unsigned int ret = 0; |
| @@ -72,97 +70,25 @@ match(const struct sk_buff *skb, | |||
| 72 | u8 _optlen, *lp = NULL; | 70 | u8 _optlen, *lp = NULL; |
| 73 | unsigned int optlen; | 71 | unsigned int optlen; |
| 74 | 72 | ||
| 75 | /* type of the 1st exthdr */ | ||
| 76 | nexthdr = skb->nh.ipv6h->nexthdr; | ||
| 77 | /* pointer to the 1st exthdr */ | ||
| 78 | ptr = sizeof(struct ipv6hdr); | ||
| 79 | /* available length */ | ||
| 80 | len = skb->len - ptr; | ||
| 81 | temp = 0; | ||
| 82 | |||
| 83 | while (ip6t_ext_hdr(nexthdr)) { | ||
| 84 | struct ipv6_opt_hdr _hdr, *hp; | ||
| 85 | |||
| 86 | DEBUGP("ipv6_opts header iteration \n"); | ||
| 87 | |||
| 88 | /* Is there enough space for the next ext header? */ | ||
| 89 | if (len < (int)sizeof(struct ipv6_opt_hdr)) | ||
| 90 | return 0; | ||
| 91 | /* No more exthdr -> evaluate */ | ||
| 92 | if (nexthdr == NEXTHDR_NONE) { | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | /* ESP -> evaluate */ | ||
| 96 | if (nexthdr == NEXTHDR_ESP) { | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
| 101 | BUG_ON(hp == NULL); | ||
| 102 | |||
| 103 | /* Calculate the header length */ | ||
| 104 | if (nexthdr == NEXTHDR_FRAGMENT) { | ||
| 105 | hdrlen = 8; | ||
| 106 | } else if (nexthdr == NEXTHDR_AUTH) | ||
| 107 | hdrlen = (hp->hdrlen+2)<<2; | ||
| 108 | else | ||
| 109 | hdrlen = ipv6_optlen(hp); | ||
| 110 | |||
| 111 | /* OPTS -> evaluate */ | ||
| 112 | #if HOPBYHOP | 73 | #if HOPBYHOP |
| 113 | if (nexthdr == NEXTHDR_HOP) { | 74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) |
| 114 | temp |= MASK_HOPOPTS; | ||
| 115 | #else | 75 | #else |
| 116 | if (nexthdr == NEXTHDR_DEST) { | 76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) |
| 117 | temp |= MASK_DSTOPTS; | ||
| 118 | #endif | 77 | #endif |
| 119 | break; | 78 | return 0; |
| 120 | } | ||
| 121 | |||
| 122 | 79 | ||
| 123 | /* set the flag */ | 80 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); |
| 124 | switch (nexthdr){ | 81 | if (oh == NULL){ |
| 125 | case NEXTHDR_HOP: | ||
| 126 | case NEXTHDR_ROUTING: | ||
| 127 | case NEXTHDR_FRAGMENT: | ||
| 128 | case NEXTHDR_AUTH: | ||
| 129 | case NEXTHDR_DEST: | ||
| 130 | break; | ||
| 131 | default: | ||
| 132 | DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); | ||
| 133 | return 0; | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | |||
| 137 | nexthdr = hp->nexthdr; | ||
| 138 | len -= hdrlen; | ||
| 139 | ptr += hdrlen; | ||
| 140 | if ( ptr > skb->len ) { | ||
| 141 | DEBUGP("ipv6_opts: new pointer is too large! \n"); | ||
| 142 | break; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | /* OPTIONS header not found */ | ||
| 147 | #if HOPBYHOP | ||
| 148 | if ( temp != MASK_HOPOPTS ) return 0; | ||
| 149 | #else | ||
| 150 | if ( temp != MASK_DSTOPTS ) return 0; | ||
| 151 | #endif | ||
| 152 | |||
| 153 | if (len < (int)sizeof(struct ipv6_opt_hdr)){ | ||
| 154 | *hotdrop = 1; | 82 | *hotdrop = 1; |
| 155 | return 0; | 83 | return 0; |
| 156 | } | 84 | } |
| 157 | 85 | ||
| 158 | if (len < hdrlen){ | 86 | hdrlen = ipv6_optlen(oh); |
| 87 | if (skb->len - ptr < hdrlen){ | ||
| 159 | /* Packet smaller than it's length field */ | 88 | /* Packet smaller than it's length field */ |
| 160 | return 0; | 89 | return 0; |
| 161 | } | 90 | } |
| 162 | 91 | ||
| 163 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); | ||
| 164 | BUG_ON(oh == NULL); | ||
| 165 | |||
| 166 | DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); | 92 | DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); |
| 167 | 93 | ||
| 168 | DEBUGP("len %02X %04X %02X ", | 94 | DEBUGP("len %02X %04X %02X ", |
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index e39dd236fd8e..24bc0cde43a1 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c | |||
| @@ -48,87 +48,22 @@ match(const struct sk_buff *skb, | |||
| 48 | unsigned int protoff, | 48 | unsigned int protoff, |
| 49 | int *hotdrop) | 49 | int *hotdrop) |
| 50 | { | 50 | { |
| 51 | struct ip_esp_hdr _esp, *eh = NULL; | 51 | struct ip_esp_hdr _esp, *eh; |
| 52 | const struct ip6t_esp *espinfo = matchinfo; | 52 | const struct ip6t_esp *espinfo = matchinfo; |
| 53 | unsigned int temp; | ||
| 54 | int len; | ||
| 55 | u8 nexthdr; | ||
| 56 | unsigned int ptr; | 53 | unsigned int ptr; |
| 57 | 54 | ||
| 58 | /* Make sure this isn't an evil packet */ | 55 | /* Make sure this isn't an evil packet */ |
| 59 | /*DEBUGP("ipv6_esp entered \n");*/ | 56 | /*DEBUGP("ipv6_esp entered \n");*/ |
| 60 | 57 | ||
| 61 | /* type of the 1st exthdr */ | 58 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0) |
| 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) | ||
| 122 | return 0; | 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 | *hotdrop = 1; | 63 | *hotdrop = 1; |
| 126 | return 0; | 64 | return 0; |
| 127 | } | 65 | } |
| 128 | 66 | ||
| 129 | eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); | ||
| 130 | BUG_ON(eh == NULL); | ||
| 131 | |||
| 132 | DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi)); | 67 | DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi)); |
| 133 | 68 | ||
| 134 | return (eh != NULL) | 69 | return (eh != NULL) |
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 4bfa30a9bc80..085d5f8eea29 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
| @@ -48,90 +48,18 @@ match(const struct sk_buff *skb, | |||
| 48 | unsigned int protoff, | 48 | unsigned int protoff, |
| 49 | int *hotdrop) | 49 | int *hotdrop) |
| 50 | { | 50 | { |
| 51 | struct frag_hdr _frag, *fh = NULL; | 51 | struct frag_hdr _frag, *fh; |
| 52 | const struct ip6t_frag *fraginfo = matchinfo; | 52 | const struct ip6t_frag *fraginfo = matchinfo; |
| 53 | unsigned int temp; | ||
| 54 | int len; | ||
| 55 | u8 nexthdr; | ||
| 56 | unsigned int ptr; | 53 | unsigned int ptr; |
| 57 | unsigned int hdrlen = 0; | ||
| 58 | |||
| 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; | ||
| 66 | |||
| 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 | 54 | ||
| 133 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); | 55 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT) < 0) |
| 134 | BUG_ON(fh == NULL); | 56 | return 0; |
| 57 | |||
| 58 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); | ||
| 59 | if (fh == NULL){ | ||
| 60 | *hotdrop = 1; | ||
| 61 | return 0; | ||
| 62 | } | ||
| 135 | 63 | ||
| 136 | DEBUGP("INFO %04X ", fh->frag_off); | 64 | DEBUGP("INFO %04X ", fh->frag_off); |
| 137 | DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); | 65 | DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); |
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 27f3650d127e..1d09485111d0 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
| @@ -63,8 +63,6 @@ match(const struct sk_buff *skb, | |||
| 63 | struct ipv6_opt_hdr _optsh, *oh; | 63 | struct ipv6_opt_hdr _optsh, *oh; |
| 64 | const struct ip6t_opts *optinfo = matchinfo; | 64 | const struct ip6t_opts *optinfo = matchinfo; |
| 65 | unsigned int temp; | 65 | unsigned int temp; |
| 66 | unsigned int len; | ||
| 67 | u8 nexthdr; | ||
| 68 | unsigned int ptr; | 66 | unsigned int ptr; |
| 69 | unsigned int hdrlen = 0; | 67 | unsigned int hdrlen = 0; |
| 70 | unsigned int ret = 0; | 68 | unsigned int ret = 0; |
| @@ -72,97 +70,25 @@ match(const struct sk_buff *skb, | |||
| 72 | u8 _optlen, *lp = NULL; | 70 | u8 _optlen, *lp = NULL; |
| 73 | unsigned int optlen; | 71 | unsigned int optlen; |
| 74 | 72 | ||
| 75 | /* type of the 1st exthdr */ | ||
| 76 | nexthdr = skb->nh.ipv6h->nexthdr; | ||
| 77 | /* pointer to the 1st exthdr */ | ||
| 78 | ptr = sizeof(struct ipv6hdr); | ||
| 79 | /* available length */ | ||
| 80 | len = skb->len - ptr; | ||
| 81 | temp = 0; | ||
| 82 | |||
| 83 | while (ip6t_ext_hdr(nexthdr)) { | ||
| 84 | struct ipv6_opt_hdr _hdr, *hp; | ||
| 85 | |||
| 86 | DEBUGP("ipv6_opts header iteration \n"); | ||
| 87 | |||
| 88 | /* Is there enough space for the next ext header? */ | ||
| 89 | if (len < (int)sizeof(struct ipv6_opt_hdr)) | ||
| 90 | return 0; | ||
| 91 | /* No more exthdr -> evaluate */ | ||
| 92 | if (nexthdr == NEXTHDR_NONE) { | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | /* ESP -> evaluate */ | ||
| 96 | if (nexthdr == NEXTHDR_ESP) { | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
| 101 | BUG_ON(hp == NULL); | ||
| 102 | |||
| 103 | /* Calculate the header length */ | ||
| 104 | if (nexthdr == NEXTHDR_FRAGMENT) { | ||
| 105 | hdrlen = 8; | ||
| 106 | } else if (nexthdr == NEXTHDR_AUTH) | ||
| 107 | hdrlen = (hp->hdrlen+2)<<2; | ||
| 108 | else | ||
| 109 | hdrlen = ipv6_optlen(hp); | ||
| 110 | |||
| 111 | /* OPTS -> evaluate */ | ||
| 112 | #if HOPBYHOP | 73 | #if HOPBYHOP |
| 113 | if (nexthdr == NEXTHDR_HOP) { | 74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) |
| 114 | temp |= MASK_HOPOPTS; | ||
| 115 | #else | 75 | #else |
| 116 | if (nexthdr == NEXTHDR_DEST) { | 76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) |
| 117 | temp |= MASK_DSTOPTS; | ||
| 118 | #endif | 77 | #endif |
| 119 | break; | 78 | return 0; |
| 120 | } | ||
| 121 | |||
| 122 | 79 | ||
| 123 | /* set the flag */ | 80 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); |
| 124 | switch (nexthdr){ | 81 | if (oh == NULL){ |
| 125 | case NEXTHDR_HOP: | ||
| 126 | case NEXTHDR_ROUTING: | ||
| 127 | case NEXTHDR_FRAGMENT: | ||
| 128 | case NEXTHDR_AUTH: | ||
| 129 | case NEXTHDR_DEST: | ||
| 130 | break; | ||
| 131 | default: | ||
| 132 | DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); | ||
| 133 | return 0; | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | |||
| 137 | nexthdr = hp->nexthdr; | ||
| 138 | len -= hdrlen; | ||
| 139 | ptr += hdrlen; | ||
| 140 | if ( ptr > skb->len ) { | ||
| 141 | DEBUGP("ipv6_opts: new pointer is too large! \n"); | ||
| 142 | break; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | /* OPTIONS header not found */ | ||
| 147 | #if HOPBYHOP | ||
| 148 | if ( temp != MASK_HOPOPTS ) return 0; | ||
| 149 | #else | ||
| 150 | if ( temp != MASK_DSTOPTS ) return 0; | ||
| 151 | #endif | ||
| 152 | |||
| 153 | if (len < (int)sizeof(struct ipv6_opt_hdr)){ | ||
| 154 | *hotdrop = 1; | 82 | *hotdrop = 1; |
| 155 | return 0; | 83 | return 0; |
| 156 | } | 84 | } |
| 157 | 85 | ||
| 158 | if (len < hdrlen){ | 86 | hdrlen = ipv6_optlen(oh); |
| 87 | if (skb->len - ptr < hdrlen){ | ||
| 159 | /* Packet smaller than it's length field */ | 88 | /* Packet smaller than it's length field */ |
| 160 | return 0; | 89 | return 0; |
| 161 | } | 90 | } |
| 162 | 91 | ||
| 163 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); | ||
| 164 | BUG_ON(oh == NULL); | ||
| 165 | |||
| 166 | DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); | 92 | DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); |
| 167 | 93 | ||
| 168 | DEBUGP("len %02X %04X %02X ", | 94 | DEBUGP("len %02X %04X %02X ", |
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 2bb670037df3..beb2fd5cebbb 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
| @@ -50,98 +50,29 @@ match(const struct sk_buff *skb, | |||
| 50 | unsigned int protoff, | 50 | unsigned int protoff, |
| 51 | int *hotdrop) | 51 | int *hotdrop) |
| 52 | { | 52 | { |
| 53 | struct ipv6_rt_hdr _route, *rh = NULL; | 53 | struct ipv6_rt_hdr _route, *rh; |
| 54 | const struct ip6t_rt *rtinfo = matchinfo; | 54 | const struct ip6t_rt *rtinfo = matchinfo; |
| 55 | unsigned int temp; | 55 | unsigned int temp; |
| 56 | unsigned int len; | ||
| 57 | u8 nexthdr; | ||
| 58 | unsigned int ptr; | 56 | unsigned int ptr; |
| 59 | unsigned int hdrlen = 0; | 57 | unsigned int hdrlen = 0; |
| 60 | unsigned int ret = 0; | 58 | unsigned int ret = 0; |
| 61 | struct in6_addr *ap, _addr; | 59 | struct in6_addr *ap, _addr; |
| 62 | 60 | ||
| 63 | /* type of the 1st exthdr */ | 61 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING) < 0) |
| 64 | nexthdr = skb->nh.ipv6h->nexthdr; | 62 | return 0; |
| 65 | /* pointer to the 1st exthdr */ | ||
| 66 | ptr = sizeof(struct ipv6hdr); | ||
| 67 | /* available length */ | ||
| 68 | len = skb->len - ptr; | ||
| 69 | temp = 0; | ||
| 70 | 63 | ||
| 71 | while (ip6t_ext_hdr(nexthdr)) { | 64 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); |
| 72 | struct ipv6_opt_hdr _hdr, *hp; | 65 | if (rh == NULL){ |
| 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)){ | ||
| 133 | *hotdrop = 1; | 66 | *hotdrop = 1; |
| 134 | return 0; | 67 | return 0; |
| 135 | } | 68 | } |
| 136 | 69 | ||
| 137 | if (len < hdrlen){ | 70 | hdrlen = ipv6_optlen(rh); |
| 71 | if (skb->len - ptr < hdrlen){ | ||
| 138 | /* Pcket smaller than its length field */ | 72 | /* Pcket smaller than its length field */ |
| 139 | return 0; | 73 | return 0; |
| 140 | } | 74 | } |
| 141 | 75 | ||
| 142 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); | ||
| 143 | BUG_ON(rh == NULL); | ||
| 144 | |||
| 145 | DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen); | 76 | DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen); |
| 146 | DEBUGP("TYPE %04X ", rh->type); | 77 | DEBUGP("TYPE %04X ", rh->type); |
| 147 | DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left); | 78 | DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left); |
