diff options
Diffstat (limited to 'sysdep/bsd/sysio.h')
-rw-r--r-- | sysdep/bsd/sysio.h | 298 |
1 files changed, 122 insertions, 176 deletions
diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index e45deb6f..fa3969bd 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -1,11 +1,16 @@ /* - * BIRD Internet Routing Daemon -- NetBSD Multicasting and Network Includes + * BIRD Internet Routing Daemon -- BSD Multicasting and Network Includes * * (c) 2004 Ondrej Filip <feela@network.cz> * * Can be freely distributed and used under the terms of the GNU GPL. */ +#include <net/if_dl.h> +#include <netinet/in_systm.h> // Workaround for some BSDs +#include <netinet/ip.h> + + #ifdef __NetBSD__ #ifndef IP_RECVTTL @@ -22,173 +27,117 @@ #define TCP_MD5SIG TCP_SIGNATURE_ENABLE #endif -#ifdef IPV6 -static inline void -set_inaddr(struct in6_addr * ia, ip_addr a) -{ - ipa_hton(a); - memcpy(ia, &a, sizeof(a)); -} +#define SA_LEN(x) (x).sa.sa_len -static inline void -get_inaddr(ip_addr *a, struct in6_addr *ia) -{ - memcpy(a, ia, sizeof(*a)); - ipa_ntoh(*a); -} - - -#else - -#include <net/if.h> -#include <net/if_dl.h> -#include <netinet/in_systm.h> // Workaround for some BSDs -#include <netinet/ip.h> - -static inline void -set_inaddr(struct in_addr * ia, ip_addr a) -{ - ipa_hton(a); - memcpy(&ia->s_addr, &a, sizeof(a)); -} - -static inline void -get_inaddr(ip_addr *a, struct in_addr *ia) -{ - memcpy(a, &ia->s_addr, sizeof(*a)); - ipa_ntoh(*a); -} +/* + * BSD IPv4 multicast syscalls + */ -/* BSD Multicast handling for IPv4 */ +#define INIT_MREQ4(maddr,ifa) \ + { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) } -static inline char * -sysio_setup_multicast(sock *s) +static inline int +sk_setup_multicast4(sock *s) { - struct in_addr m; - u8 zero = 0; - u8 ttl = s->ttl; + struct in_addr ifa = ipa_to_in4(s->iface->addr->ip); + u8 ttl = s->ttl; + u8 n = 0; - if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) - return "IP_MULTICAST_LOOP"; + /* This defines where should we send _outgoing_ multicasts */ + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &ifa, sizeof(ifa)) < 0) + ERR("IP_MULTICAST_IF"); - if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) - return "IP_MULTICAST_TTL"; + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) + ERR("IP_MULTICAST_TTL"); - /* This defines where should we send _outgoing_ multicasts */ - set_inaddr(&m, s->iface->addr->ip); - if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0) - return "IP_MULTICAST_IF"; + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0) + ERR("IP_MULTICAST_LOOP"); - return NULL; + return 0; } - -static inline char * -sysio_join_group(sock *s, ip_addr maddr) +static inline int +sk_join_group4(sock *s, ip_addr maddr) { - struct ip_mreq mreq; + struct ip_mreq mr = INIT_MREQ4(maddr, s->iface); - bzero(&mreq, sizeof(mreq)); - set_inaddr(&mreq.imr_interface, s->iface->addr->ip); - set_inaddr(&mreq.imr_multiaddr, maddr); + if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) + ERR("IP_ADD_MEMBERSHIP"); - /* And this one sets interface for _receiving_ multicasts from */ - if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) - return "IP_ADD_MEMBERSHIP"; - - return NULL; + return 0; } -static inline char * -sysio_leave_group(sock *s, ip_addr maddr) +static inline int +sk_leave_group4(sock *s, ip_addr maddr) { - struct ip_mreq mreq; + struct ip_mreq mr = INIT_MREQ4(maddr, s->iface); - bzero(&mreq, sizeof(mreq)); - set_inaddr(&mreq.imr_interface, s->iface->addr->ip); - set_inaddr(&mreq.imr_multiaddr, maddr); + if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0) + ERR("IP_ADD_MEMBERSHIP"); - /* And this one sets interface for _receiving_ multicasts from */ - if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) - return "IP_DROP_MEMBERSHIP"; - - return NULL; + return 0; } -/* BSD RX/TX packet info handling for IPv4 */ -/* it uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */ +/* + * BSD IPv4 packet control messages + */ -#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + \ - CMSG_SPACE(sizeof(struct sockaddr_dl)) + \ - CMSG_SPACE(sizeof(char))) -#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_addr)) +/* It uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */ -static char * -sysio_register_cmsgs(sock *s) -{ - int ok = 1; - if (s->flags & SKF_LADDR_RX) - { - if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0) - return "IP_RECVDSTADDR"; +#define CMSG4_SPACE_PKTINFO (CMSG_SPACE(sizeof(struct in_addr)) + \ + CMSG_SPACE(sizeof(struct sockaddr_dl))) +#define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(char)) - if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0) - return "IP_RECVIF"; - } +static inline int +sk_request_cmsg4_pktinfo(sock *s) +{ + int y = 1; - if ((s->flags & SKF_TTL_RX) && - (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0)) - return "IP_RECVTTL"; + if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &y, sizeof(y)) < 0) + ERR("IP_RECVDSTADDR"); + if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &y, sizeof(y)) < 0) + ERR("IP_RECVIF"); - return NULL; + return 0; } -static inline void -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) +static inline int +sk_request_cmsg4_ttl(sock *s) { - struct cmsghdr *cm; - struct in_addr *ra = NULL; - struct sockaddr_dl *ri = NULL; - unsigned char *ttl = NULL; - - for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) - { - if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR) - ra = (struct in_addr *) CMSG_DATA(cm); - - if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF) - ri = (struct sockaddr_dl *) CMSG_DATA(cm); - - if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVTTL) - ttl = (unsigned char *) CMSG_DATA(cm); - } + int y = 1; - if (s->flags & SKF_LADDR_RX) - { - s->laddr = IPA_NONE; - s->lifindex = 0; + if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &y, sizeof(y)) < 0) + ERR("IP_RECVTTL"); - if (ra) - get_inaddr(&s->laddr, ra); - if (ri) - s->lifindex = ri->sdl_index; - } + return 0; +} - if (s->flags & SKF_TTL_RX) - s->ttl = ttl ? *ttl : -1; +static inline void +sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm) +{ + if (cm->cmsg_type == IP_RECVDSTADDR) + s->laddr = ipa_from_in4(* (struct in_addr *) CMSG_DATA(cm)); - // log(L_WARN "RX %I %d", s->laddr, s->lifindex); + if (cm->cmsg_type == IP_RECVIF) + s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index; } -/* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */ +static inline void +sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm) +{ + if (cm->cmsg_type == IP_RECVTTL) + s->rcv_ttl = * (unsigned char *) CMSG_DATA(cm); +} static inline void -sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) +sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) { + /* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */ + #ifdef IP_SENDSRCADDR struct cmsghdr *cm; struct in_addr *sa; @@ -202,15 +151,14 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) cm->cmsg_len = CMSG_LEN(sizeof(*sa)); sa = (struct in_addr *) CMSG_DATA(cm); - set_inaddr(sa, s->saddr); + *sa = ipa_to_in4(s->saddr); msg->msg_controllen = cm->cmsg_len; #endif } - static void -fill_ip_header(sock *s, void *hdr, int dlen) +sk_prepare_ip_header(sock *s, void *hdr, int dlen) { struct ip *ip = hdr; @@ -222,8 +170,8 @@ fill_ip_header(sock *s, void *hdr, int dlen) ip->ip_len = 20 + dlen; ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl; ip->ip_p = s->dport; - set_inaddr(&ip->ip_src, s->saddr); - set_inaddr(&ip->ip_dst, s->daddr); + ip->ip_src = ipa_to_in4(s->saddr); + ip->ip_dst = ipa_to_in4(s->daddr); #ifdef __OpenBSD__ /* OpenBSD expects ip_len in network order, other BSDs expect host order */ @@ -231,10 +179,11 @@ fill_ip_header(sock *s, void *hdr, int dlen) #endif } -#endif +/* + * Miscellaneous BSD socket syscalls + */ -#include <netinet/tcp.h> #ifndef TCP_KEYLEN_MAX #define TCP_KEYLEN_MAX 80 #endif @@ -248,72 +197,69 @@ fill_ip_header(sock *s, void *hdr, int dlen) * management. */ -static int -sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd) +int +sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd) { int enable = 0; - if (passwd) - { - int len = strlen(passwd); - - enable = len ? TCP_SIG_SPI : 0; - - if (len > TCP_KEYLEN_MAX) - { - log(L_ERR "MD5 password too long"); - return -1; - } - } - - int rv = setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)); - - if (rv < 0) - { - if (errno == ENOPROTOOPT) - log(L_ERR "Kernel does not support TCP MD5 signatures"); - else - log(L_ERR "sk_set_md5_auth_int: setsockopt: %m"); - } - - return rv; -} + if (passwd && *passwd) + { + int len = strlen(passwd); + enable = TCP_SIG_SPI; + + if (len > TCP_KEYLEN_MAX) + ERR_MSG("MD5 password too long"); + } + + if (setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)) < 0) + { + if (errno == ENOPROTOOPT) + ERR_MSG("Kernel does not support TCP MD5 signatures"); + else + ERR("TCP_MD5SIG"); + } -#ifndef IPV6 + return 0; +} -static int +static inline int sk_set_min_ttl4(sock *s, int ttl) { if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) { if (errno == ENOPROTOOPT) - log(L_ERR "Kernel does not support IPv4 TTL security"); + ERR_MSG("Kernel does not support IPv4 TTL security"); else - log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); - - return -1; + ERR("IP_MINTTL"); } return 0; } -#else /* IPv6 */ - -static int +static inline int sk_set_min_ttl6(sock *s, int ttl) { - log(L_ERR "IPv6 TTL security not supported"); - return -1; + ERR_MSG("Kernel does not support IPv6 TTL security"); } -#endif +static inline int +sk_disable_mtu_disc4(sock *s) +{ + /* TODO: Set IP_DONTFRAG to 0 ? */ + return 0; +} +static inline int +sk_disable_mtu_disc6(sock *s) +{ + /* TODO: Set IPV6_DONTFRAG to 0 ? */ + return 0; +} int sk_priority_control = -1; -static int +static inline int sk_set_priority(sock *s, int prio UNUSED) { - log(L_WARN "Socket priority not supported"); - return -1; + ERR_MSG("Socket priority not supported"); } |