Skip to content

Commit cfb6eeb

Browse files
yoshfujiDavid S. Miller
authored andcommitted
[TCP]: MD5 Signature Option (RFC2385) support.
Based on implementation by Rick Payne. Signed-off-by: YOSHIFUJI Hideaki <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bf6bce7 commit cfb6eeb

File tree

15 files changed

+1714
-64
lines changed

15 files changed

+1714
-64
lines changed

CREDITS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,6 +2598,9 @@ S: Ucitelska 1576
25982598
S: Prague 8
25992599
S: 182 00 Czech Republic
26002600

2601+
N: Rick Payne
2602+
D: RFC2385 Support for TCP
2603+
26012604
N: Barak A. Pearlmutter
26022605
26032606
W: http://www.cs.unm.edu/~bap/

include/linux/tcp.h

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <linux/types.h>
2121
#include <asm/byteorder.h>
22+
#include <linux/socket.h>
2223

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

98100
#define TCPI_OPT_TIMESTAMPS 1
99101
#define TCPI_OPT_SACK 2
@@ -157,6 +159,17 @@ struct tcp_info
157159
__u32 tcpi_total_retrans;
158160
};
159161

162+
/* for TCP_MD5SIG socket option */
163+
#define TCP_MD5SIG_MAXKEYLEN 80
164+
165+
struct tcp_md5sig {
166+
struct __kernel_sockaddr_storage tcpm_addr; /* address associated */
167+
__u16 __tcpm_pad1; /* zero */
168+
__u16 tcpm_keylen; /* key length */
169+
__u32 __tcpm_pad2; /* zero */
170+
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
171+
};
172+
160173
#ifdef __KERNEL__
161174

162175
#include <linux/skbuff.h>
@@ -197,9 +210,13 @@ struct tcp_options_received {
197210
};
198211

199212
struct tcp_request_sock {
200-
struct inet_request_sock req;
201-
__u32 rcv_isn;
202-
__u32 snt_isn;
213+
struct inet_request_sock req;
214+
#ifdef CONFIG_TCP_MD5SIG
215+
/* Only used by TCP MD5 Signature so far. */
216+
struct tcp_request_sock_ops *af_specific;
217+
#endif
218+
__u32 rcv_isn;
219+
__u32 snt_isn;
203220
};
204221

205222
static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
@@ -363,6 +380,14 @@ struct tcp_sock {
363380
__u32 probe_seq_start;
364381
__u32 probe_seq_end;
365382
} mtu_probe;
383+
384+
#ifdef CONFIG_TCP_MD5SIG
385+
/* TCP AF-Specific parts; only used by MD5 Signature support so far */
386+
struct tcp_sock_af_ops *af_specific;
387+
388+
/* TCP MD5 Signagure Option information */
389+
struct tcp_md5sig_info *md5sig_info;
390+
#endif
366391
};
367392

368393
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
@@ -377,6 +402,10 @@ struct tcp_timewait_sock {
377402
__u32 tw_rcv_wnd;
378403
__u32 tw_ts_recent;
379404
long tw_ts_recent_stamp;
405+
#ifdef CONFIG_TCP_MD5SIG
406+
__u16 tw_md5_keylen;
407+
__u8 tw_md5_key[TCP_MD5SIG_MAXKEYLEN];
408+
#endif
380409
};
381410

382411
static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)

include/net/request_sock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ struct request_sock_ops {
3535
struct dst_entry *dst);
3636
void (*send_ack)(struct sk_buff *skb,
3737
struct request_sock *req);
38-
void (*send_reset)(struct sk_buff *skb);
38+
void (*send_reset)(struct sock *sk,
39+
struct sk_buff *skb);
3940
void (*destructor)(struct request_sock *req);
4041
};
4142

include/net/tcp.h

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/percpu.h>
2929
#include <linux/skbuff.h>
3030
#include <linux/dmaengine.h>
31+
#include <linux/crypto.h>
3132

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

165167
/*
166168
* TCP option lengths
@@ -170,6 +172,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
170172
#define TCPOLEN_WINDOW 3
171173
#define TCPOLEN_SACK_PERM 2
172174
#define TCPOLEN_TIMESTAMP 10
175+
#define TCPOLEN_MD5SIG 18
173176

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

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

306+
extern void tcp_twsk_destructor(struct sock *sk);
307+
302308
static inline void tcp_dec_quickack_mode(struct sock *sk,
303309
const unsigned int pkts)
304310
{
@@ -1064,6 +1070,114 @@ static inline void clear_all_retrans_hints(struct tcp_sock *tp){
10641070
tp->fastpath_skb_hint = NULL;
10651071
}
10661072

1073+
/* MD5 Signature */
1074+
struct crypto_hash;
1075+
1076+
/* - key database */
1077+
struct tcp_md5sig_key {
1078+
u8 *key;
1079+
u8 keylen;
1080+
};
1081+
1082+
struct tcp4_md5sig_key {
1083+
u8 *key;
1084+
u16 keylen;
1085+
__be32 addr;
1086+
};
1087+
1088+
struct tcp6_md5sig_key {
1089+
u8 *key;
1090+
u16 keylen;
1091+
#if 0
1092+
u32 scope_id; /* XXX */
1093+
#endif
1094+
struct in6_addr addr;
1095+
};
1096+
1097+
/* - sock block */
1098+
struct tcp_md5sig_info {
1099+
struct tcp4_md5sig_key *keys4;
1100+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1101+
struct tcp6_md5sig_key *keys6;
1102+
u32 entries6;
1103+
u32 alloced6;
1104+
#endif
1105+
u32 entries4;
1106+
u32 alloced4;
1107+
};
1108+
1109+
/* - pseudo header */
1110+
struct tcp4_pseudohdr {
1111+
__be32 saddr;
1112+
__be32 daddr;
1113+
__u8 pad;
1114+
__u8 protocol;
1115+
__be16 len;
1116+
};
1117+
1118+
struct tcp6_pseudohdr {
1119+
struct in6_addr saddr;
1120+
struct in6_addr daddr;
1121+
__be32 len;
1122+
__be32 protocol; /* including padding */
1123+
};
1124+
1125+
union tcp_md5sum_block {
1126+
struct tcp4_pseudohdr ip4;
1127+
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1128+
struct tcp6_pseudohdr ip6;
1129+
#endif
1130+
};
1131+
1132+
/* - pool: digest algorithm, hash description and scratch buffer */
1133+
struct tcp_md5sig_pool {
1134+
struct hash_desc md5_desc;
1135+
union tcp_md5sum_block md5_blk;
1136+
};
1137+
1138+
#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */
1139+
1140+
/* - functions */
1141+
extern int tcp_v4_calc_md5_hash(char *md5_hash,
1142+
struct tcp_md5sig_key *key,
1143+
struct sock *sk,
1144+
struct dst_entry *dst,
1145+
struct request_sock *req,
1146+
struct tcphdr *th,
1147+
int protocol, int tcplen);
1148+
extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
1149+
struct sock *addr_sk);
1150+
1151+
extern int tcp_v4_md5_do_add(struct sock *sk,
1152+
__be32 addr,
1153+
u8 *newkey,
1154+
u8 newkeylen);
1155+
1156+
extern int tcp_v4_md5_do_del(struct sock *sk,
1157+
u32 addr);
1158+
1159+
extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void);
1160+
extern void tcp_free_md5sig_pool(void);
1161+
1162+
extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu);
1163+
extern void __tcp_put_md5sig_pool(void);
1164+
1165+
static inline
1166+
struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
1167+
{
1168+
int cpu = get_cpu();
1169+
struct tcp_md5sig_pool *ret = __tcp_get_md5sig_pool(cpu);
1170+
if (!ret)
1171+
put_cpu();
1172+
return ret;
1173+
}
1174+
1175+
static inline void tcp_put_md5sig_pool(void)
1176+
{
1177+
__tcp_put_md5sig_pool();
1178+
put_cpu();
1179+
}
1180+
10671181
/* /proc */
10681182
enum tcp_seq_states {
10691183
TCP_SEQ_STATE_LISTENING,
@@ -1103,6 +1217,35 @@ extern int tcp4_proc_init(void);
11031217
extern void tcp4_proc_exit(void);
11041218
#endif
11051219

1220+
/* TCP af-specific functions */
1221+
struct tcp_sock_af_ops {
1222+
#ifdef CONFIG_TCP_MD5SIG
1223+
struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk,
1224+
struct sock *addr_sk);
1225+
int (*calc_md5_hash) (char *location,
1226+
struct tcp_md5sig_key *md5,
1227+
struct sock *sk,
1228+
struct dst_entry *dst,
1229+
struct request_sock *req,
1230+
struct tcphdr *th,
1231+
int protocol, int len);
1232+
int (*md5_add) (struct sock *sk,
1233+
struct sock *addr_sk,
1234+
u8 *newkey,
1235+
u8 len);
1236+
int (*md5_parse) (struct sock *sk,
1237+
char __user *optval,
1238+
int optlen);
1239+
#endif
1240+
};
1241+
1242+
struct tcp_request_sock_ops {
1243+
#ifdef CONFIG_TCP_MD5SIG
1244+
struct tcp_md5sig_key *(*md5_lookup) (struct sock *sk,
1245+
struct request_sock *req);
1246+
#endif
1247+
};
1248+
11061249
extern void tcp_v4_init(struct net_proto_family *ops);
11071250
extern void tcp_init(void);
11081251

include/net/timewait_sock.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
3131

3232
static inline void twsk_destructor(struct sock *sk)
3333
{
34+
BUG_ON(sk == NULL);
35+
BUG_ON(sk->sk_prot == NULL);
36+
BUG_ON(sk->sk_prot->twsk_prot == NULL);
3437
if (sk->sk_prot->twsk_prot->twsk_destructor != NULL)
3538
sk->sk_prot->twsk_prot->twsk_destructor(sk);
3639
}

net/dccp/ipv4.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
509509
return err;
510510
}
511511

512-
static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
512+
static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
513513
{
514514
int err;
515515
struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
@@ -724,7 +724,7 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
724724
return 0;
725725

726726
reset:
727-
dccp_v4_ctl_send_reset(skb);
727+
dccp_v4_ctl_send_reset(sk, skb);
728728
discard:
729729
kfree_skb(skb);
730730
return 0;
@@ -913,7 +913,7 @@ static int dccp_v4_rcv(struct sk_buff *skb)
913913
if (dh->dccph_type != DCCP_PKT_RESET) {
914914
DCCP_SKB_CB(skb)->dccpd_reset_code =
915915
DCCP_RESET_CODE_NO_CONNECTION;
916-
dccp_v4_ctl_send_reset(skb);
916+
dccp_v4_ctl_send_reset(sk, skb);
917917
}
918918

919919
discard_it:

net/dccp/ipv6.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ static void dccp_v6_reqsk_destructor(struct request_sock *req)
310310
kfree_skb(inet6_rsk(req)->pktopts);
311311
}
312312

313-
static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
313+
static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
314314
{
315315
struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
316316
const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
@@ -805,7 +805,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
805805
return 0;
806806

807807
reset:
808-
dccp_v6_ctl_send_reset(skb);
808+
dccp_v6_ctl_send_reset(sk, skb);
809809
discard:
810810
if (opt_skb != NULL)
811811
__kfree_skb(opt_skb);
@@ -902,7 +902,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb)
902902
if (dh->dccph_type != DCCP_PKT_RESET) {
903903
DCCP_SKB_CB(skb)->dccpd_reset_code =
904904
DCCP_RESET_CODE_NO_CONNECTION;
905-
dccp_v6_ctl_send_reset(skb);
905+
dccp_v6_ctl_send_reset(sk, skb);
906906
}
907907

908908
discard_it:

net/dccp/minisocks.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
246246
DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
247247
drop:
248248
if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET)
249-
req->rsk_ops->send_reset(skb);
249+
req->rsk_ops->send_reset(sk, skb);
250250

251251
inet_csk_reqsk_queue_drop(sk, req, prev);
252252
goto out;

net/ipv4/Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,5 +618,21 @@ config DEFAULT_TCP_CONG
618618
default "reno" if DEFAULT_RENO
619619
default "cubic"
620620

621+
config TCP_MD5SIG
622+
bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)"
623+
depends on EXPERIMENTAL
624+
select CRYPTO
625+
select CRYPTO_MD5
626+
---help---
627+
RFC2385 specifices a method of giving MD5 protection to TCP sessions.
628+
Its main (only?) use is to protect BGP sessions between core routers
629+
on the Internet.
630+
631+
If unsure, say N.
632+
633+
config TCP_MD5SIG_DEBUG
634+
bool "TCP: MD5 Signature Option debugging"
635+
depends on TCP_MD5SIG
636+
621637
source "net/ipv4/ipvs/Kconfig"
622638

0 commit comments

Comments
 (0)