Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d5d5525 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki
Browse files

tcp md5sig: Share MD5 Signature option parser between IPv4 and IPv6.

parent 81b302a3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -399,6 +399,8 @@ extern void tcp_parse_options(struct sk_buff *skb,
						  struct tcp_options_received *opt_rx,
						  int estab);

extern u8			*tcp_parse_md5sig_option(struct tcphdr *th);

/*
 *	TCP v4 functions exported for the inet6 API
 */
+40 −0
Original line number Diff line number Diff line
@@ -3450,6 +3450,43 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
	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)
{
	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_adv_win_scale);
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_state_process);
EXPORT_SYMBOL(tcp_initialize_rcv_mss);
+1 −41
Original line number Diff line number Diff line
@@ -1134,52 +1134,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
	struct tcp_md5sig_key *hash_expected;
	const struct iphdr *iph = ip_hdr(skb);
	struct tcphdr *th = tcp_hdr(skb);
	int length = (th->doff << 2) - sizeof(struct tcphdr);
	int genhash;
	unsigned char *ptr;
	unsigned char newhash[16];

	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? */
	if (!hash_expected && !hash_location)
		return 0;
+1 −32
Original line number Diff line number Diff line
@@ -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 ipv6hdr *ip6h = ipv6_hdr(skb);
	struct tcphdr *th = tcp_hdr(skb);
	int length = (th->doff << 2) - sizeof (*th);
	int genhash;
	u8 *ptr;
	u8 newhash[16];

	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? */
	if (!hash_expected) {
		if (!hash_location)