diff --git a/lib/socket.h b/lib/socket.h index 03c15dcd..f2b0c042 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -106,7 +106,7 @@ int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface int sk_setup_broadcast(sock *s); int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */ int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */ -int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey); +int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, char *passwd, int setkey); int sk_set_ipv6_checksum(sock *s, int offset); int sk_set_icmp6_filter(sock *s, int p1, int p2); void sk_log_error(sock *s, const char *p); diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 83105a68..b9ed6c78 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -247,8 +247,17 @@ bgp_setup_auth(struct bgp_proto *p, int enable) { if (p->cf->password) { + ip_addr prefix = p->cf->remote_ip; + int pxlen = -1; + + if (p->cf->remote_range) + { + prefix = net_prefix(p->cf->remote_range); + pxlen = net_pxlen(p->cf->remote_range); + } + int rv = sk_set_md5_auth(p->sock->sk, - p->cf->local_ip, p->cf->remote_ip, p->cf->iface, + p->cf->local_ip, prefix, pxlen, p->cf->iface, enable ? p->cf->password : NULL, p->cf->setkey); if (rv < 0) diff --git a/sysdep/bsd/setkey.h b/sysdep/bsd/setkey.h index 8a1bc9ad..40564cf1 100644 --- a/sysdep/bsd/setkey.h +++ b/sysdep/bsd/setkey.h @@ -63,7 +63,7 @@ setkey_send(struct sadb_msg *msg, uint len) * operations to implement replace. */ static int -setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type) +setkey_md5(sockaddr *src, uint slen, sockaddr *dst, uint dlen, char *passwd, uint type) { uint passwd_len = passwd ? strlen(passwd) : 0; @@ -122,7 +122,7 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type) saddr->sadb_address_len = PFKEY_UNIT64(len); saddr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; saddr->sadb_address_proto = IPSEC_ULPROTO_ANY; - saddr->sadb_address_prefixlen = pxlen; + saddr->sadb_address_prefixlen = slen; memcpy(pos + sizeof(struct sadb_address), &src->sa, src->sa.sa_len); pos += len; @@ -132,7 +132,7 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type) daddr->sadb_address_len = PFKEY_UNIT64(len); daddr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; daddr->sadb_address_proto = IPSEC_ULPROTO_ANY; - daddr->sadb_address_prefixlen = pxlen; + daddr->sadb_address_prefixlen = dlen; memcpy(pos + sizeof(struct sadb_address), &dst->sa, dst->sa.sa_len); pos += len; @@ -146,13 +146,15 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type) * Manipulation with the IPsec SA/SP database */ static int -sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd) +sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, char *passwd) { sockaddr src, dst; sockaddr_fill(&src, s->af, local, ifa, 0); sockaddr_fill(&dst, s->af, remote, ifa, 0); - uint pxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH; + uint maxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH; + uint slen = maxlen; + uint dlen = (pxlen < 0) ? maxlen : pxlen; if (passwd && *passwd) { @@ -160,14 +162,14 @@ sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, if (len > TCP_KEYLEN_MAX) ERR_MSG("The password for TCP MD5 Signature is too long"); - if ((setkey_md5(&src, &dst, pxlen, passwd, SADB_ADD) < 0) || - (setkey_md5(&dst, &src, pxlen, passwd, SADB_ADD) < 0)) + if ((setkey_md5(&src, slen, &dst, dlen, passwd, SADB_ADD) < 0) || + (setkey_md5(&dst, dlen, &src, slen, passwd, SADB_ADD) < 0)) ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database"); } else { - if ((setkey_md5(&src, &dst, pxlen, NULL, SADB_DELETE) < 0) || - (setkey_md5(&dst, &src, pxlen, NULL, SADB_DELETE) < 0)) + if ((setkey_md5(&src, slen, &dst, dlen, NULL, SADB_DELETE) < 0) || + (setkey_md5(&dst, dlen, &src, slen, NULL, SADB_DELETE) < 0)) ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database"); } return 0; diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index a5d161ba..929bfaf6 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -210,11 +210,11 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen) #endif int -sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote UNUSED, struct iface *ifa UNUSED, char *passwd, int setkey UNUSED) +sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote UNUSED, int pxlen UNUSED, struct iface *ifa UNUSED, char *passwd, int setkey UNUSED) { #ifdef USE_MD5SIG_SETKEY if (setkey) - if (sk_set_md5_in_sasp_db(s, local, remote, ifa, passwd) < 0) + if (sk_set_md5_in_sasp_db(s, local, remote, pxlen, ifa, passwd) < 0) return -1; #endif diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index b1cc25dc..8c3efd6e 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -6,35 +6,28 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ - -#ifndef IP_MINTTL -#define IP_MINTTL 21 -#endif - -#ifndef IPV6_TCLASS -#define IPV6_TCLASS 67 -#endif - #ifndef IPV6_MINHOPCOUNT #define IPV6_MINHOPCOUNT 73 #endif - -#ifndef TCP_MD5SIG - -#define TCP_MD5SIG 14 -#define TCP_MD5SIG_MAXKEYLEN 80 - -struct tcp_md5sig { - struct 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) */ -}; - +#ifndef TCP_MD5SIG_EXT +#define TCP_MD5SIG_EXT 32 #endif +#ifndef TCP_MD5SIG_FLAG_PREFIX +#define TCP_MD5SIG_FLAG_PREFIX 1 +#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 */ + u8 tcpm_flags; /* Extension flags */ + u8 tcpm_prefixlen; /* Address prefix */ + u16 tcpm_keylen; /* Key length */ + u32 __tcpm_pad2; /* Zero */ + u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* Key (binary) */ +}; + /* Linux does not care if sa_len is larger than needed */ #define SA_LEN(x) sizeof(sockaddr) @@ -169,9 +162,9 @@ 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, struct iface *ifa, char *passwd, int setkey UNUSED) +sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, char *passwd, int setkey UNUSED) { - struct tcp_md5sig md5; + struct tcp_md5sig_ext md5; memset(&md5, 0, sizeof(md5)); sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0); @@ -187,12 +180,26 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa memcpy(&md5.tcpm_key, passwd, len); } - if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0) + if (pxlen < 0) { - if (errno == ENOPROTOOPT) - ERR_MSG("Kernel does not support TCP MD5 signatures"); - else - ERR("TCP_MD5SIG"); + if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &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; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 5e4d9573..f4e45a5f 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1442,7 +1442,7 @@ sk_open(sock *s) } if (s->password) - if (sk_set_md5_auth(s, s->saddr, s->daddr, s->iface, s->password, 0) < 0) + if (sk_set_md5_auth(s, s->saddr, s->daddr, -1, s->iface, s->password, 0) < 0) goto err; switch (s->type)