0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-18 00:58:42 +00:00
bird/sysdep/bsd/sysio.h

268 lines
5.4 KiB
C
Raw Normal View History

/*
2014-05-18 09:42:26 +00:00
* 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.
*/
2014-05-18 09:42:26 +00:00
#include <net/if_dl.h>
#include <netinet/in_systm.h> // Workaround for some BSDs
#include <netinet/ip.h>
2013-07-11 11:50:44 +00:00
#ifdef __NetBSD__
#ifndef IP_RECVTTL
#define IP_RECVTTL 23
#endif
#ifndef IP_MINTTL
#define IP_MINTTL 24
#endif
#endif
#ifdef __DragonFly__
#define TCP_MD5SIG TCP_SIGNATURE_ENABLE
#endif
2013-07-11 11:50:44 +00:00
2014-05-18 09:42:26 +00:00
#define SA_LEN(x) (x).sa.sa_len
2014-05-18 09:42:26 +00:00
/*
* BSD IPv4 multicast syscalls
*/
2014-05-18 09:42:26 +00:00
#define INIT_MREQ4(maddr,ifa) \
{ .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) }
2014-05-18 09:42:26 +00:00
static inline int
sk_setup_multicast4(sock *s)
{
2014-05-18 09:42:26 +00:00
struct in_addr ifa = ipa_to_in4(s->iface->addr->ip);
u8 ttl = s->ttl;
u8 n = 0;
2014-05-18 09:42:26 +00:00
/* 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");
2014-05-18 09:42:26 +00:00
if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
ERR("IP_MULTICAST_TTL");
2014-05-18 09:42:26 +00:00
if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0)
ERR("IP_MULTICAST_LOOP");
2014-05-18 09:42:26 +00:00
return 0;
}
2014-05-18 09:42:26 +00:00
static inline int
sk_join_group4(sock *s, ip_addr maddr)
{
2014-05-18 09:42:26 +00:00
struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
2014-05-18 09:42:26 +00:00
if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)
ERR("IP_ADD_MEMBERSHIP");
2014-05-18 09:42:26 +00:00
return 0;
}
2014-05-18 09:42:26 +00:00
static inline int
sk_leave_group4(sock *s, ip_addr maddr)
{
2014-05-18 09:42:26 +00:00
struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
2014-05-18 09:42:26 +00:00
if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0)
ERR("IP_ADD_MEMBERSHIP");
2014-05-18 09:42:26 +00:00
return 0;
}
2014-05-18 09:42:26 +00:00
/*
* BSD IPv4 packet control messages
*/
2014-05-18 09:42:26 +00:00
/* It uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
2014-05-18 09:42:26 +00:00
#define CMSG4_SPACE_PKTINFO (CMSG_SPACE(sizeof(struct in_addr)) + \
CMSG_SPACE(sizeof(struct sockaddr_dl)))
#define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(char))
2014-05-18 09:42:26 +00:00
static inline int
sk_request_cmsg4_pktinfo(sock *s)
{
int y = 1;
2014-05-18 09:42:26 +00:00
if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &y, sizeof(y)) < 0)
ERR("IP_RECVDSTADDR");
2014-05-18 09:42:26 +00:00
if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &y, sizeof(y)) < 0)
ERR("IP_RECVIF");
2014-05-18 09:42:26 +00:00
return 0;
}
2014-05-18 09:42:26 +00:00
static inline int
sk_request_cmsg4_ttl(sock *s)
{
2014-05-18 09:42:26 +00:00
int y = 1;
2014-05-18 09:42:26 +00:00
if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &y, sizeof(y)) < 0)
ERR("IP_RECVTTL");
2014-05-18 09:42:26 +00:00
return 0;
}
2014-05-18 09:42:26 +00:00
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));
2014-05-18 09:42:26 +00:00
if (cm->cmsg_type == IP_RECVIF)
s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index;
}
2014-05-18 09:42:26 +00:00
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
2014-05-18 09:42:26 +00:00
sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{
2014-05-18 09:42:26 +00:00
/* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */
#ifdef IP_SENDSRCADDR
struct cmsghdr *cm;
struct in_addr *sa;
int controllen = 0;
2010-04-02 09:31:20 +00:00
msg->msg_control = cbuf;
msg->msg_controllen = cbuflen;
cm = CMSG_FIRSTHDR(msg);
cm->cmsg_level = IPPROTO_IP;
cm->cmsg_type = IP_SENDSRCADDR;
cm->cmsg_len = CMSG_LEN(sizeof(*sa));
controllen += CMSG_SPACE(sizeof(*sa));
sa = (struct in_addr *) CMSG_DATA(cm);
2014-05-18 09:42:26 +00:00
*sa = ipa_to_in4(s->saddr);
msg->msg_controllen = controllen;
#endif
}
static void
2014-05-18 09:42:26 +00:00
sk_prepare_ip_header(sock *s, void *hdr, int dlen)
{
struct ip *ip = hdr;
bzero(ip, 20);
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_tos = (s->tos < 0) ? 0 : s->tos;
ip->ip_len = 20 + dlen;
ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl;
ip->ip_p = s->dport;
2014-05-18 09:42:26 +00:00
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 */
ip->ip_len = htons(ip->ip_len);
#endif
}
2014-05-18 09:42:26 +00:00
/*
* Miscellaneous BSD socket syscalls
*/
#ifndef TCP_KEYLEN_MAX
#define TCP_KEYLEN_MAX 80
#endif
#ifndef TCP_SIG_SPI
#define TCP_SIG_SPI 0x1000
#endif
/*
* FIXME: Passwords has to be set by setkey(8) command. This is the same
* behaviour like Quagga. We need to add code for SA/SP entries
* management.
*/
2014-05-18 09:42:26 +00:00
int
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
{
int enable = 0;
2014-05-18 09:42:26 +00:00
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");
}
2014-05-18 09:42:26 +00:00
return 0;
}
2014-05-18 09:42:26 +00:00
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)
2014-05-18 09:42:26 +00:00
ERR_MSG("Kernel does not support IPv4 TTL security");
else
2014-05-18 09:42:26 +00:00
ERR("IP_MINTTL");
}
return 0;
}
2014-05-18 09:42:26 +00:00
static inline int
sk_set_min_ttl6(sock *s, int ttl)
{
2014-05-18 09:42:26 +00:00
ERR_MSG("Kernel does not support IPv6 TTL security");
}
2014-05-18 09:42:26 +00:00
static inline int
sk_disable_mtu_disc4(sock *s)
{
/* TODO: Set IP_DONTFRAG to 0 ? */
return 0;
}
2014-05-18 09:42:26 +00:00
static inline int
sk_disable_mtu_disc6(sock *s)
{
/* TODO: Set IPV6_DONTFRAG to 0 ? */
return 0;
}
int sk_priority_control = -1;
2014-05-18 09:42:26 +00:00
static inline int
sk_set_priority(sock *s, int prio UNUSED)
{
2014-05-18 09:42:26 +00:00
ERR_MSG("Socket priority not supported");
}