Skip to content

Commit

Permalink
[TCP]: MD5 Signature Option (RFC2385) support.
Browse files Browse the repository at this point in the history
Based on implementation by Rick Payne.

Signed-off-by: YOSHIFUJI Hideaki <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
yoshfuji authored and David S. Miller committed Dec 3, 2006
1 parent bf6bce7 commit cfb6eeb
Show file tree
Hide file tree
Showing 15 changed files with 1,714 additions and 64 deletions.
3 changes: 3 additions & 0 deletions CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -2598,6 +2598,9 @@ S: Ucitelska 1576
S: Prague 8
S: 182 00 Czech Republic

N: Rick Payne
D: RFC2385 Support for TCP

N: Barak A. Pearlmutter
E: [email protected]
W: http://www.cs.unm.edu/~bap/
Expand Down
35 changes: 32 additions & 3 deletions include/linux/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/socket.h>

struct tcphdr {
__be16 source;
Expand Down Expand Up @@ -94,6 +95,7 @@ enum {
#define TCP_INFO 11 /* Information about this connection. */
#define TCP_QUICKACK 12 /* Block/reenable quick acks */
#define TCP_CONGESTION 13 /* Congestion control algorithm */
#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */

#define TCPI_OPT_TIMESTAMPS 1
#define TCPI_OPT_SACK 2
Expand Down Expand Up @@ -157,6 +159,17 @@ struct tcp_info
__u32 tcpi_total_retrans;
};

/* for TCP_MD5SIG socket option */
#define TCP_MD5SIG_MAXKEYLEN 80

struct tcp_md5sig {
struct __kernel_sockaddr_storage tcpm_addr; /* address associated */
__u16 __tcpm_pad1; /* zero */
__u16 tcpm_keylen; /* key length */
__u32 __tcpm_pad2; /* zero */
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
};

#ifdef __KERNEL__

#include <linux/skbuff.h>
Expand Down Expand Up @@ -197,9 +210,13 @@ struct tcp_options_received {
};

struct tcp_request_sock {
struct inet_request_sock req;
__u32 rcv_isn;
__u32 snt_isn;
struct inet_request_sock req;
#ifdef CONFIG_TCP_MD5SIG
/* Only used by TCP MD5 Signature so far. */
struct tcp_request_sock_ops *af_specific;
#endif
__u32 rcv_isn;
__u32 snt_isn;
};

static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
Expand Down Expand Up @@ -363,6 +380,14 @@ struct tcp_sock {
__u32 probe_seq_start;
__u32 probe_seq_end;
} mtu_probe;

#ifdef CONFIG_TCP_MD5SIG
/* TCP AF-Specific parts; only used by MD5 Signature support so far */
struct tcp_sock_af_ops *af_specific;

/* TCP MD5 Signagure Option information */
struct tcp_md5sig_info *md5sig_info;
#endif
};

static inline struct tcp_sock *tcp_sk(const struct sock *sk)
Expand All @@ -377,6 +402,10 @@ struct tcp_timewait_sock {
__u32 tw_rcv_wnd;
__u32 tw_ts_recent;
long tw_ts_recent_stamp;
#ifdef CONFIG_TCP_MD5SIG
__u16 tw_md5_keylen;
__u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN];
#endif
};

static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)
Expand Down
3 changes: 2 additions & 1 deletion include/net/request_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ struct request_sock_ops {
struct dst_entry *dst);
void (*send_ack)(struct sk_buff *skb,
struct request_sock *req);
void (*send_reset)(struct sk_buff *skb);
void (*send_reset)(struct sock *sk,
struct sk_buff *skb);
void (*destructor)(struct request_sock *req);
};

Expand Down
143 changes: 143 additions & 0 deletions include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/percpu.h>
#include <linux/skbuff.h>
#include <linux/dmaengine.h>
#include <linux/crypto.h>

#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
Expand Down Expand Up @@ -161,6 +162,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOPT_SACK_PERM 4 /* SACK Permitted */
#define TCPOPT_SACK 5 /* SACK Block */
#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */

/*
* TCP option lengths
Expand All @@ -170,6 +172,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOLEN_WINDOW 3
#define TCPOLEN_SACK_PERM 2
#define TCPOLEN_TIMESTAMP 10
#define TCPOLEN_MD5SIG 18

/* But this is what stacks really send out. */
#define TCPOLEN_TSTAMP_ALIGNED 12
Expand All @@ -178,6 +181,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOLEN_SACK_BASE 2
#define TCPOLEN_SACK_BASE_ALIGNED 4
#define TCPOLEN_SACK_PERBLOCK 8
#define TCPOLEN_MD5SIG_ALIGNED 20

/* Flags in tp->nonagle */
#define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */
Expand Down Expand Up @@ -299,6 +303,8 @@ extern void tcp_cleanup_rbuf(struct sock *sk, int copied);
extern int tcp_twsk_unique(struct sock *sk,
struct sock *sktw, void *twp);

extern void tcp_twsk_destructor(struct sock *sk);

static inline void tcp_dec_quickack_mode(struct sock *sk,
const unsigned int pkts)
{
Expand Down Expand Up @@ -1064,6 +1070,114 @@ static inline void clear_all_retrans_hints(struct tcp_sock *tp){
tp->fastpath_skb_hint = NULL;
}

/* MD5 Signature */
struct crypto_hash;

/* - key database */
struct tcp_md5sig_key {
u8 *key;
u8 keylen;
};

struct tcp4_md5sig_key {
u8 *key;
u16 keylen;
__be32 addr;
};

struct tcp6_md5sig_key {
u8 *key;
u16 keylen;
#if 0
u32 scope_id; /* XXX */
#endif
struct in6_addr addr;
};

/* - sock block */
struct tcp_md5sig_info {
struct tcp4_md5sig_key *keys4;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct tcp6_md5sig_key *keys6;
u32 entries6;
u32 alloced6;
#endif
u32 entries4;
u32 alloced4;
};

/* - pseudo header */
struct tcp4_pseudohdr {
__be32 saddr;
__be32 daddr;
__u8 pad;
__u8 protocol;
__be16 len;
};

struct tcp6_pseudohdr {
struct in6_addr saddr;
struct in6_addr daddr;
__be32 len;
__be32 protocol; /* including padding */
};

union tcp_md5sum_block {
struct tcp4_pseudohdr ip4;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct tcp6_pseudohdr ip6;
#endif
};

/* - pool: digest algorithm, hash description and scratch buffer */
struct tcp_md5sig_pool {
struct hash_desc md5_desc;
union tcp_md5sum_block md5_blk;
};

#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */

/* - functions */
extern int tcp_v4_calc_md5_hash(char *md5_hash,
struct tcp_md5sig_key *key,
struct sock *sk,
struct dst_entry *dst,
struct request_sock *req,
struct tcphdr *th,
int protocol, int tcplen);
extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
struct sock *addr_sk);

extern int tcp_v4_md5_do_add(struct sock *sk,
__be32 addr,
u8 *newkey,
u8 newkeylen);

extern int tcp_v4_md5_do_del(struct sock *sk,
u32 addr);

extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void);
extern void tcp_free_md5sig_pool(void);

extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu);
extern void __tcp_put_md5sig_pool(void);

static inline
struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
{
int cpu = get_cpu();
struct tcp_md5sig_pool *ret = __tcp_get_md5sig_pool(cpu);
if (!ret)
put_cpu();
return ret;
}

static inline void tcp_put_md5sig_pool(void)
{
__tcp_put_md5sig_pool();
put_cpu();
}

/* /proc */
enum tcp_seq_states {
TCP_SEQ_STATE_LISTENING,
Expand Down Expand Up @@ -1103,6 +1217,35 @@ extern int tcp4_proc_init(void);
extern void tcp4_proc_exit(void);
#endif

/* TCP af-specific functions */
struct tcp_sock_af_ops {
#ifdef CONFIG_TCP_MD5SIG
struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk,
struct sock *addr_sk);
int (*calc_md5_hash) (char *location,
struct tcp_md5sig_key *md5,
struct sock *sk,
struct dst_entry *dst,
struct request_sock *req,
struct tcphdr *th,
int protocol, int len);
int (*md5_add) (struct sock *sk,
struct sock *addr_sk,
u8 *newkey,
u8 len);
int (*md5_parse) (struct sock *sk,
char __user *optval,
int optlen);
#endif
};

struct tcp_request_sock_ops {
#ifdef CONFIG_TCP_MD5SIG
struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk,
struct request_sock *req);
#endif
};

extern void tcp_v4_init(struct net_proto_family *ops);
extern void tcp_init(void);

Expand Down
3 changes: 3 additions & 0 deletions include/net/timewait_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)

static inline void twsk_destructor(struct sock *sk)
{
BUG_ON(sk == NULL);
BUG_ON(sk->sk_prot == NULL);
BUG_ON(sk->sk_prot->twsk_prot == NULL);
if (sk->sk_prot->twsk_prot->twsk_destructor != NULL)
sk->sk_prot->twsk_prot->twsk_destructor(sk);
}
Expand Down
6 changes: 3 additions & 3 deletions net/dccp/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
return err;
}

static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
{
int err;
struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
Expand Down Expand Up @@ -724,7 +724,7 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;

reset:
dccp_v4_ctl_send_reset(skb);
dccp_v4_ctl_send_reset(sk, skb);
discard:
kfree_skb(skb);
return 0;
Expand Down Expand Up @@ -913,7 +913,7 @@ static int dccp_v4_rcv(struct sk_buff *skb)
if (dh->dccph_type != DCCP_PKT_RESET) {
DCCP_SKB_CB(skb)->dccpd_reset_code =
DCCP_RESET_CODE_NO_CONNECTION;
dccp_v4_ctl_send_reset(skb);
dccp_v4_ctl_send_reset(sk, skb);
}

discard_it:
Expand Down
6 changes: 3 additions & 3 deletions net/dccp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req)
kfree_skb(inet6_rsk(req)->pktopts);
}

static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
{
struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
Expand Down Expand Up @@ -805,7 +805,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;

reset:
dccp_v6_ctl_send_reset(skb);
dccp_v6_ctl_send_reset(sk, skb);
discard:
if (opt_skb != NULL)
__kfree_skb(opt_skb);
Expand Down Expand Up @@ -902,7 +902,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
if (dh->dccph_type != DCCP_PKT_RESET) {
DCCP_SKB_CB(skb)->dccpd_reset_code =
DCCP_RESET_CODE_NO_CONNECTION;
dccp_v6_ctl_send_reset(skb);
dccp_v6_ctl_send_reset(sk, skb);
}

discard_it:
Expand Down
2 changes: 1 addition & 1 deletion net/dccp/minisocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
drop:
if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
req->rsk_ops->send_reset(skb);
req->rsk_ops->send_reset(sk, skb);

inet_csk_reqsk_queue_drop(sk, req, prev);
goto out;
Expand Down
16 changes: 16 additions & 0 deletions net/ipv4/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -618,5 +618,21 @@ config DEFAULT_TCP_CONG
default "reno" if DEFAULT_RENO
default "cubic"

config TCP_MD5SIG
bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)"
depends on EXPERIMENTAL
select CRYPTO
select CRYPTO_MD5
---help---
RFC2385 specifices a method of giving MD5 protection to TCP sessions.
Its main (only?) use is to protect BGP sessions between core routers
on the Internet.

If unsure, say N.

config TCP_MD5SIG_DEBUG
bool "TCP: MD5 Signature Option debugging"
depends on TCP_MD5SIG

source "net/ipv4/ipvs/Kconfig"

Loading

0 comments on commit cfb6eeb

Please sign in to comment.