diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-04-16 23:29:53 -0400 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-06-11 13:38:18 -0400 |
commit | 7d5d5525bd88313e6fd90c0659665aee5114bc2d (patch) | |
tree | 41517e753220261c8cc46d975977cfd711892f6c | |
parent | 81b302a321a0d99ff172b8cb2a8de17bff2f9499 (diff) |
tcp md5sig: Share MD5 Signature option parser between IPv4 and IPv6.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
-rw-r--r-- | include/net/tcp.h | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 40 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 42 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 33 |
4 files changed, 44 insertions, 73 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 633147cb6bbc..b1c4b78f1cb8 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -399,6 +399,8 @@ extern void tcp_parse_options(struct sk_buff *skb, | |||
399 | struct tcp_options_received *opt_rx, | 399 | struct tcp_options_received *opt_rx, |
400 | int estab); | 400 | int estab); |
401 | 401 | ||
402 | extern u8 *tcp_parse_md5sig_option(struct tcphdr *th); | ||
403 | |||
402 | /* | 404 | /* |
403 | * TCP v4 functions exported for the inet6 API | 405 | * TCP v4 functions exported for the inet6 API |
404 | */ | 406 | */ |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index eba873e9b560..f331e67f2328 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -3450,6 +3450,43 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, | |||
3450 | return 1; | 3450 | return 1; |
3451 | } | 3451 | } |
3452 | 3452 | ||
3453 | #ifdef CONFIG_TCP_MD5SIG | ||
3454 | /* | ||
3455 | * Parse MD5 Signature option | ||
3456 | */ | ||
3457 | u8 *tcp_parse_md5sig_option(struct tcphdr *th) | ||
3458 | { | ||
3459 | int length = (th->doff << 2) - sizeof (*th); | ||
3460 | u8 *ptr = (u8*)(th + 1); | ||
3461 | |||
3462 | /* If the TCP option is too short, we can short cut */ | ||
3463 | if (length < TCPOLEN_MD5SIG) | ||
3464 | return NULL; | ||
3465 | |||
3466 | while (length > 0) { | ||
3467 | int opcode = *ptr++; | ||
3468 | int opsize; | ||
3469 | |||
3470 | switch(opcode) { | ||
3471 | case TCPOPT_EOL: | ||
3472 | return NULL; | ||
3473 | case TCPOPT_NOP: | ||
3474 | length--; | ||
3475 | continue; | ||
3476 | default: | ||
3477 | opsize = *ptr++; | ||
3478 | if (opsize < 2 || opsize > length) | ||
3479 | return NULL; | ||
3480 | if (opcode == TCPOPT_MD5SIG) | ||
3481 | return ptr; | ||
3482 | } | ||
3483 | ptr += opsize - 2; | ||
3484 | length -= opsize; | ||
3485 | } | ||
3486 | return NULL; | ||
3487 | } | ||
3488 | #endif | ||
3489 | |||
3453 | static inline void tcp_store_ts_recent(struct tcp_sock *tp) | 3490 | static inline void tcp_store_ts_recent(struct tcp_sock *tp) |
3454 | { | 3491 | { |
3455 | tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval; | 3492 | tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval; |
@@ -5467,6 +5504,9 @@ EXPORT_SYMBOL(sysctl_tcp_ecn); | |||
5467 | EXPORT_SYMBOL(sysctl_tcp_reordering); | 5504 | EXPORT_SYMBOL(sysctl_tcp_reordering); |
5468 | EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); | 5505 | EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); |
5469 | EXPORT_SYMBOL(tcp_parse_options); | 5506 | EXPORT_SYMBOL(tcp_parse_options); |
5507 | #ifdef CONFIG_TCP_MD5SIG | ||
5508 | EXPORT_SYMBOL(tcp_parse_md5sig_option); | ||
5509 | #endif | ||
5470 | EXPORT_SYMBOL(tcp_rcv_established); | 5510 | EXPORT_SYMBOL(tcp_rcv_established); |
5471 | EXPORT_SYMBOL(tcp_rcv_state_process); | 5511 | EXPORT_SYMBOL(tcp_rcv_state_process); |
5472 | EXPORT_SYMBOL(tcp_initialize_rcv_mss); | 5512 | EXPORT_SYMBOL(tcp_initialize_rcv_mss); |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cd601a866c2f..56f550933644 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1134,52 +1134,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | |||
1134 | struct tcp_md5sig_key *hash_expected; | 1134 | struct tcp_md5sig_key *hash_expected; |
1135 | const struct iphdr *iph = ip_hdr(skb); | 1135 | const struct iphdr *iph = ip_hdr(skb); |
1136 | struct tcphdr *th = tcp_hdr(skb); | 1136 | struct tcphdr *th = tcp_hdr(skb); |
1137 | int length = (th->doff << 2) - sizeof(struct tcphdr); | ||
1138 | int genhash; | 1137 | int genhash; |
1139 | unsigned char *ptr; | ||
1140 | unsigned char newhash[16]; | 1138 | unsigned char newhash[16]; |
1141 | 1139 | ||
1142 | hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); | 1140 | hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); |
1141 | hash_location = tcp_parse_md5sig_option(th); | ||
1143 | 1142 | ||
1144 | /* | ||
1145 | * If the TCP option length is less than the TCP_MD5SIG | ||
1146 | * option length, then we can shortcut | ||
1147 | */ | ||
1148 | if (length < TCPOLEN_MD5SIG) { | ||
1149 | if (hash_expected) | ||
1150 | return 1; | ||
1151 | else | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | /* Okay, we can't shortcut - we have to grub through the options */ | ||
1156 | ptr = (unsigned char *)(th + 1); | ||
1157 | while (length > 0) { | ||
1158 | int opcode = *ptr++; | ||
1159 | int opsize; | ||
1160 | |||
1161 | switch (opcode) { | ||
1162 | case TCPOPT_EOL: | ||
1163 | goto done_opts; | ||
1164 | case TCPOPT_NOP: | ||
1165 | length--; | ||
1166 | continue; | ||
1167 | default: | ||
1168 | opsize = *ptr++; | ||
1169 | if (opsize < 2) | ||
1170 | goto done_opts; | ||
1171 | if (opsize > length) | ||
1172 | goto done_opts; | ||
1173 | |||
1174 | if (opcode == TCPOPT_MD5SIG) { | ||
1175 | hash_location = ptr; | ||
1176 | goto done_opts; | ||
1177 | } | ||
1178 | } | ||
1179 | ptr += opsize-2; | ||
1180 | length -= opsize; | ||
1181 | } | ||
1182 | done_opts: | ||
1183 | /* We've parsed the options - do we have a hash? */ | 1143 | /* We've parsed the options - do we have a hash? */ |
1184 | if (!hash_expected && !hash_location) | 1144 | if (!hash_expected && !hash_location) |
1185 | return 0; | 1145 | return 0; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 715965f0fac0..dd4ddb30a3a9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -844,43 +844,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
844 | struct tcp_md5sig_key *hash_expected; | 844 | struct tcp_md5sig_key *hash_expected; |
845 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 845 | struct ipv6hdr *ip6h = ipv6_hdr(skb); |
846 | struct tcphdr *th = tcp_hdr(skb); | 846 | struct tcphdr *th = tcp_hdr(skb); |
847 | int length = (th->doff << 2) - sizeof (*th); | ||
848 | int genhash; | 847 | int genhash; |
849 | u8 *ptr; | ||
850 | u8 newhash[16]; | 848 | u8 newhash[16]; |
851 | 849 | ||
852 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); | 850 | hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); |
851 | hash_location = tcp_parse_md5sig_option(th); | ||
853 | 852 | ||
854 | /* If the TCP option is too short, we can short cut */ | ||
855 | if (length < TCPOLEN_MD5SIG) | ||
856 | return hash_expected ? 1 : 0; | ||
857 | |||
858 | /* parse options */ | ||
859 | ptr = (u8*)(th + 1); | ||
860 | while (length > 0) { | ||
861 | int opcode = *ptr++; | ||
862 | int opsize; | ||
863 | |||
864 | switch(opcode) { | ||
865 | case TCPOPT_EOL: | ||
866 | goto done_opts; | ||
867 | case TCPOPT_NOP: | ||
868 | length--; | ||
869 | continue; | ||
870 | default: | ||
871 | opsize = *ptr++; | ||
872 | if (opsize < 2 || opsize > length) | ||
873 | goto done_opts; | ||
874 | if (opcode == TCPOPT_MD5SIG) { | ||
875 | hash_location = ptr; | ||
876 | goto done_opts; | ||
877 | } | ||
878 | } | ||
879 | ptr += opsize - 2; | ||
880 | length -= opsize; | ||
881 | } | ||
882 | |||
883 | done_opts: | ||
884 | /* do we have a hash as expected? */ | 853 | /* do we have a hash as expected? */ |
885 | if (!hash_expected) { | 854 | if (!hash_expected) { |
886 | if (!hash_location) | 855 | if (!hash_location) |