diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index f13eda7c..1aa78ab9 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -6,6 +6,8 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +#include "sysdep/linux/tcp-ao.h" + #ifndef IPV6_MINHOPCOUNT #define IPV6_MINHOPCOUNT 73 #endif @@ -22,6 +24,15 @@ #define TCP_MD5SIG_FLAG_PREFIX 1 #endif +#ifndef TCP_AO_ADD_KEY +#define TCP_AO_ADD_KEY 38 /* Add/Set MKT */ +#define TCP_AO_DEL_KEY 39 /* Delete MKT */ +#define TCP_AO_INFO 40 /* Set/list TCP-AO per-socket options */ +#define TCP_AO_GET_KEYS 41 /* List MKT(s) */ +#define TCP_AO_REPAIR 42 /* Get/Set SNEs and ISNs */ + +#endif + /* We redefine the tcp_md5sig structure with different name to avoid collision with older headers */ struct tcp_md5sig_ext { struct sockaddr_storage tcpm_addr; /* Address associated */ @@ -166,7 +177,7 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) */ int -sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey UNUSED) +sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey UNUSED) // local UNUSED { struct tcp_md5sig_ext md5; @@ -184,6 +195,69 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct memcpy(&md5.tcpm_key, passwd, len); } + if (pxlen < 0) + { + struct tcp_ao_add_ext ao; + memset(&ao, 0, sizeof(struct tcp_ao_add_ext)); + sockaddr_fill((sockaddr *) &ao.addr, s->af, remote, ifa, 0); + ao.set_current = 0; + ao.set_rnext = 0; + ao.prefix = -1; + ao.sndid = 100; + ao.rcvid = 100; + ao.maclen = 0; + ao.keyflags = 0; + ao.keylen = strlen(passwd); + ao.ifindex = 0; + + memcpy(ao.key, passwd, (strlen(passwd) > TCP_AO_MAXKEYLEN_) ? TCP_AO_MAXKEYLEN_ : strlen(passwd)); + + int IPPROTO_TCP_ = 6; + if (setsockopt(s->fd, SOL_TCP, TCP_AO_ADD_KEY, &md5, sizeof(md5)) < 0) + bug("tcp ao err %i", errno); + log("ok"); + /*if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG_EXT, &md5, sizeof(md5)) < 0) + if (errno == ENOPROTOOPT) + ERR_MSG("Kernel does not support TCP MD5 signatures"); + else + ERR("TCP_MD5SIG");*/ + } + else + { + md5.tcpm_flags = TCP_MD5SIG_FLAG_PREFIX; + md5.tcpm_prefixlen = pxlen; + + if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG_EXT, &md5, sizeof(md5)) < 0) + { + if (errno == ENOPROTOOPT) + ERR_MSG("Kernel does not support extended TCP MD5 signatures"); + else + ERR("TCP_MD5SIG_EXT"); + } + } + + return 0; +} + +/**int +sk_set_tcpao_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey UNUSED) +{ + struct tcp_ao_add *ao; + + memset(&ao, 0, sizeof(struct tcp_ao_add)); + sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0); + + if (passwd) + { + int len = strlen(passwd); + + if (len > TCP_MD5SIG_MAXKEYLEN) + ERR_MSG("The password for TCP MD5 Signature is too long"); + + md5.tcpm_keylen = len; + memcpy(&md5.tcpm_key, passwd, len); + } + if (pxlen < 0) { if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0) @@ -207,7 +281,7 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct } return 0; -} +}**/ static inline int sk_set_min_ttl4(sock *s, int ttl) diff --git a/sysdep/linux/tcp-ao.h b/sysdep/linux/tcp-ao.h new file mode 100644 index 00000000..523952cc --- /dev/null +++ b/sysdep/linux/tcp-ao.h @@ -0,0 +1,95 @@ + +#define TCP_AO_MAXKEYLEN_ 80 + +#define DEFAULT_TEST_ALGO "cmac(aes128)" + +struct tcp_ao_add_ext { /* setsockopt(TCP_AO_ADD_KEY) */ + struct sockaddr_storage addr; /* peer's address for the key */ + char alg_name[64]; /* crypto hash algorithm to use */ + s32 ifindex; /* L3 dev index for VRF */ + u32 set_current :1, /* set key as Current_key at once */ + set_rnext :1, /* request it from peer with RNext_key */ + reserved :30; /* must be 0 */ + u16 reserved2; /* padding, must be 0 */ + u8 prefix; /* peer's address prefix */ + u8 sndid; /* SendID for outgoing segments */ + u8 rcvid; /* RecvID to match for incoming seg */ + u8 maclen; /* length of authentication code (hash) */ + u8 keyflags; /* see TCP_AO_KEYF_ */ + u8 keylen; /* length of ::key */ + u8 key[TCP_AO_MAXKEYLEN_]; +} __attribute__((aligned(8))); + +struct tcp_ao_del_ext { /* setsockopt(TCP_AO_DEL_KEY) */ + struct sockaddr_storage addr; /* peer's address for the key */ + s32 ifindex; /* L3 dev index for VRF */ + u32 set_current :1, /* corresponding ::current_key */ + set_rnext :1, /* corresponding ::rnext */ + del_async :1, /* only valid for listen sockets */ + reserved :29; /* must be 0 */ + u16 reserved2; /* padding, must be 0 */ + u8 prefix; /* peer's address prefix */ + u8 sndid; /* SendID for outgoing segments */ + u8 rcvid; /* RecvID to match for incoming seg */ + u8 current_key; /* KeyID to set as Current_key */ + u8 rnext; /* KeyID to set as Rnext_key */ + u8 keyflags; /* see TCP_AO_KEYF_ */ +} __attribute__((aligned(8))); + +struct tcp_ao_info_opt_ext { /* setsockopt(TCP_AO_INFO), getsockopt(TCP_AO_INFO) */ + /* Here 'in' is for setsockopt(), 'out' is for getsockopt() */ + u32 set_current :1, /* in/out: corresponding ::current_key */ + set_rnext :1, /* in/out: corresponding ::rnext */ + ao_required :1, /* in/out: don't accept non-AO connects */ + set_counters :1, /* in: set/clear ::pkt_* counters */ + accept_icmps :1, /* in/out: accept incoming ICMPs */ + reserved :27; /* must be 0 */ + u16 reserved2; /* padding, must be 0 */ + u8 current_key; /* in/out: KeyID of Current_key */ + u8 rnext; /* in/out: keyid of RNext_key */ + u64 pkt_good; /* in/out: verified segments */ + u64 pkt_bad; /* in/out: failed verification */ + u64 pkt_key_not_found; /* in/out: could not find a key to verify */ + u64 pkt_ao_required; /* in/out: segments missing TCP-AO sign */ + u64 pkt_dropped_icmp; /* in/out: ICMPs that were ignored */ +} __attribute__((aligned(8))); + +struct tcp_ao_getsockopt_ext { /* getsockopt(TCP_AO_GET_KEYS) */ + struct sockaddr_storage addr; /* in/out: dump keys for peer + * with this address/prefix + */ + char alg_name[64]; /* out: crypto hash algorithm */ + u8 key[TCP_AO_MAXKEYLEN_]; + u32 nkeys; /* in: size of the userspace buffer + * @optval, measured in @optlen - the + * sizeof(struct tcp_ao_getsockopt) + * out: number of keys that matched + */ + u16 is_current :1, /* in: match and dump Current_key, + * out: the dumped key is Current_key + */ + + is_rnext :1, /* in: match and dump RNext_key, + * out: the dumped key is RNext_key + */ + get_all :1, /* in: dump all keys */ + reserved :13; /* padding, must be 0 */ + u8 sndid; /* in/out: dump keys with SendID */ + u8 rcvid; /* in/out: dump keys with RecvID */ + u8 prefix; /* in/out: dump keys with address/prefix */ + u8 maclen; /* out: key's length of authentication + * code (hash) + */ + u8 keyflags; /* in/out: see TCP_AO_KEYF_ */ + u8 keylen; /* out: length of ::key */ + s32 ifindex; /* in/out: L3 dev index for VRF */ + u64 pkt_good; /* out: verified segments */ + u64 pkt_bad; /* out: segments that failed verification */ +} __attribute__((aligned(8))); + +struct tcp_ao_repair_ext { /* {s,g}etsockopt(TCP_AO_REPAIR) */ + u32 snt_isn; //should be __be32 alias fdt32_t - 32-bit, big-endian, unsigned integer + u32 rcv_isn; //should be __be32 alias fdt32_t - 32-bit, big-endian, unsigned integer + u32 snd_sne; + u32 rcv_sne; +} __attribute__((aligned(8)));