tcp md5sig: Share MD5 Signature option parser between IPv4 and IPv6.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
This commit is contained in:
@@ -399,6 +399,8 @@ extern void tcp_parse_options(struct sk_buff *skb,
|
|||||||
struct tcp_options_received *opt_rx,
|
struct tcp_options_received *opt_rx,
|
||||||
int estab);
|
int estab);
|
||||||
|
|
||||||
|
extern u8 *tcp_parse_md5sig_option(struct tcphdr *th);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TCP v4 functions exported for the inet6 API
|
* TCP v4 functions exported for the inet6 API
|
||||||
*/
|
*/
|
||||||
|
@@ -3450,6 +3450,43 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCP_MD5SIG
|
||||||
|
/*
|
||||||
|
* Parse MD5 Signature option
|
||||||
|
*/
|
||||||
|
u8 *tcp_parse_md5sig_option(struct tcphdr *th)
|
||||||
|
{
|
||||||
|
int length = (th->doff << 2) - sizeof (*th);
|
||||||
|
u8 *ptr = (u8*)(th + 1);
|
||||||
|
|
||||||
|
/* If the TCP option is too short, we can short cut */
|
||||||
|
if (length < TCPOLEN_MD5SIG)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
int opcode = *ptr++;
|
||||||
|
int opsize;
|
||||||
|
|
||||||
|
switch(opcode) {
|
||||||
|
case TCPOPT_EOL:
|
||||||
|
return NULL;
|
||||||
|
case TCPOPT_NOP:
|
||||||
|
length--;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
opsize = *ptr++;
|
||||||
|
if (opsize < 2 || opsize > length)
|
||||||
|
return NULL;
|
||||||
|
if (opcode == TCPOPT_MD5SIG)
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
ptr += opsize - 2;
|
||||||
|
length -= opsize;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void tcp_store_ts_recent(struct tcp_sock *tp)
|
static inline void tcp_store_ts_recent(struct tcp_sock *tp)
|
||||||
{
|
{
|
||||||
tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
|
tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
|
||||||
@@ -5467,6 +5504,9 @@ EXPORT_SYMBOL(sysctl_tcp_ecn);
|
|||||||
EXPORT_SYMBOL(sysctl_tcp_reordering);
|
EXPORT_SYMBOL(sysctl_tcp_reordering);
|
||||||
EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
|
EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
|
||||||
EXPORT_SYMBOL(tcp_parse_options);
|
EXPORT_SYMBOL(tcp_parse_options);
|
||||||
|
#ifdef CONFIG_TCP_MD5SIG
|
||||||
|
EXPORT_SYMBOL(tcp_parse_md5sig_option);
|
||||||
|
#endif
|
||||||
EXPORT_SYMBOL(tcp_rcv_established);
|
EXPORT_SYMBOL(tcp_rcv_established);
|
||||||
EXPORT_SYMBOL(tcp_rcv_state_process);
|
EXPORT_SYMBOL(tcp_rcv_state_process);
|
||||||
EXPORT_SYMBOL(tcp_initialize_rcv_mss);
|
EXPORT_SYMBOL(tcp_initialize_rcv_mss);
|
||||||
|
@@ -1134,52 +1134,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
|
|||||||
struct tcp_md5sig_key *hash_expected;
|
struct tcp_md5sig_key *hash_expected;
|
||||||
const struct iphdr *iph = ip_hdr(skb);
|
const struct iphdr *iph = ip_hdr(skb);
|
||||||
struct tcphdr *th = tcp_hdr(skb);
|
struct tcphdr *th = tcp_hdr(skb);
|
||||||
int length = (th->doff << 2) - sizeof(struct tcphdr);
|
|
||||||
int genhash;
|
int genhash;
|
||||||
unsigned char *ptr;
|
|
||||||
unsigned char newhash[16];
|
unsigned char newhash[16];
|
||||||
|
|
||||||
hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr);
|
hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr);
|
||||||
|
hash_location = tcp_parse_md5sig_option(th);
|
||||||
|
|
||||||
/*
|
|
||||||
* If the TCP option length is less than the TCP_MD5SIG
|
|
||||||
* option length, then we can shortcut
|
|
||||||
*/
|
|
||||||
if (length < TCPOLEN_MD5SIG) {
|
|
||||||
if (hash_expected)
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Okay, we can't shortcut - we have to grub through the options */
|
|
||||||
ptr = (unsigned char *)(th + 1);
|
|
||||||
while (length > 0) {
|
|
||||||
int opcode = *ptr++;
|
|
||||||
int opsize;
|
|
||||||
|
|
||||||
switch (opcode) {
|
|
||||||
case TCPOPT_EOL:
|
|
||||||
goto done_opts;
|
|
||||||
case TCPOPT_NOP:
|
|
||||||
length--;
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
opsize = *ptr++;
|
|
||||||
if (opsize < 2)
|
|
||||||
goto done_opts;
|
|
||||||
if (opsize > length)
|
|
||||||
goto done_opts;
|
|
||||||
|
|
||||||
if (opcode == TCPOPT_MD5SIG) {
|
|
||||||
hash_location = ptr;
|
|
||||||
goto done_opts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ptr += opsize-2;
|
|
||||||
length -= opsize;
|
|
||||||
}
|
|
||||||
done_opts:
|
|
||||||
/* We've parsed the options - do we have a hash? */
|
/* We've parsed the options - do we have a hash? */
|
||||||
if (!hash_expected && !hash_location)
|
if (!hash_expected && !hash_location)
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -844,43 +844,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
|
|||||||
struct tcp_md5sig_key *hash_expected;
|
struct tcp_md5sig_key *hash_expected;
|
||||||
struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||||
struct tcphdr *th = tcp_hdr(skb);
|
struct tcphdr *th = tcp_hdr(skb);
|
||||||
int length = (th->doff << 2) - sizeof (*th);
|
|
||||||
int genhash;
|
int genhash;
|
||||||
u8 *ptr;
|
|
||||||
u8 newhash[16];
|
u8 newhash[16];
|
||||||
|
|
||||||
hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
|
hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
|
||||||
|
hash_location = tcp_parse_md5sig_option(th);
|
||||||
|
|
||||||
/* If the TCP option is too short, we can short cut */
|
|
||||||
if (length < TCPOLEN_MD5SIG)
|
|
||||||
return hash_expected ? 1 : 0;
|
|
||||||
|
|
||||||
/* parse options */
|
|
||||||
ptr = (u8*)(th + 1);
|
|
||||||
while (length > 0) {
|
|
||||||
int opcode = *ptr++;
|
|
||||||
int opsize;
|
|
||||||
|
|
||||||
switch(opcode) {
|
|
||||||
case TCPOPT_EOL:
|
|
||||||
goto done_opts;
|
|
||||||
case TCPOPT_NOP:
|
|
||||||
length--;
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
opsize = *ptr++;
|
|
||||||
if (opsize < 2 || opsize > length)
|
|
||||||
goto done_opts;
|
|
||||||
if (opcode == TCPOPT_MD5SIG) {
|
|
||||||
hash_location = ptr;
|
|
||||||
goto done_opts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ptr += opsize - 2;
|
|
||||||
length -= opsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
done_opts:
|
|
||||||
/* do we have a hash as expected? */
|
/* do we have a hash as expected? */
|
||||||
if (!hash_expected) {
|
if (!hash_expected) {
|
||||||
if (!hash_location)
|
if (!hash_location)
|
||||||
|
Reference in New Issue
Block a user