IPv4/IPv6 integrated socket code.

This commit is contained in:
Ondrej Zajicek 2014-05-18 11:42:26 +02:00
parent 1149aa977d
commit 05476c4d04
16 changed files with 1361 additions and 1267 deletions

View file

@ -19,7 +19,6 @@
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/string.h" #include "lib/string.h"
#include "client/client.h" #include "client/client.h"
#include "sysdep/unix/unix.h"
static int input_hidden_end; static int input_hidden_end;
static int prompt_active; static int prompt_active;

View file

@ -221,6 +221,16 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
continue; continue;
case 'm': case 'm':
if (flags & SPECIAL) {
if (!errno)
continue;
if (size < 2)
return -1;
*str++ = ':';
*str++ = ' ';
start += 2;
size -= 2;
}
s = strerror(errno); s = strerror(errno);
goto str; goto str;
case 'M': case 'M':

View file

@ -10,6 +10,7 @@
#define _BIRD_SOCKET_H_ #define _BIRD_SOCKET_H_
#include <errno.h> #include <errno.h>
// #include <sys/socket.h>
#include "lib/resource.h" #include "lib/resource.h"
@ -43,17 +44,21 @@ typedef struct birdsock {
unsigned lifindex; /* local interface that received the datagram */ unsigned lifindex; /* local interface that received the datagram */
/* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */ /* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */
int af; /* Address family (AF_INET, AF_INET6 or 0 for non-IP) of fd */
int fd; /* System-dependent data */ int fd; /* System-dependent data */
int index; /* Index in poll buffer */ int index; /* Index in poll buffer */
int rcv_ttl; /* TTL of last received datagram */
node n; node n;
void *rbuf_alloc, *tbuf_alloc; void *rbuf_alloc, *tbuf_alloc;
char *password; /* Password for MD5 authentication */ char *password; /* Password for MD5 authentication */
char *err; /* Error message */
} sock; } sock;
sock *sock_new(pool *); /* Allocate new socket */ sock *sock_new(pool *); /* Allocate new socket */
#define sk_new(X) sock_new(X) /* Wrapper to avoid name collision with OpenSSL */ #define sk_new(X) sock_new(X) /* Wrapper to avoid name collision with OpenSSL */
int sk_open(sock *); /* Open socket */ int sk_open(sock *); /* Open socket */
int sk_rx_ready(sock *s);
int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */ int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */
int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */ int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */
void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */ void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */
@ -61,39 +66,41 @@ void sk_set_rbsize(sock *s, uint val); /* Resize RX buffer */
void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */ void sk_set_tbsize(sock *s, uint val); /* Resize TX buffer, keeping content */
void sk_set_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */ void sk_set_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */
void sk_dump_all(void); void sk_dump_all(void);
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 */
/* Add or remove security associations for given passive socket */ static inline int sk_send_buffer_empty(sock *sk)
int sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd); { return sk->tbuf == sk->tpos; }
int sk_rx_ready(sock *s);
/* Prepare UDP or IP socket to multicasting. s->iface and s->ttl must be set */
int sk_setup_multicast(sock *s);
int sk_join_group(sock *s, ip_addr maddr);
int sk_leave_group(sock *s, ip_addr maddr);
#ifdef IPV6 #ifdef IPV6
int sk_set_ipv6_checksum(sock *s, int offset); #define sk_is_ipv4(X) 0
int sk_set_icmp_filter(sock *s, int p1, int p2); #define sk_is_ipv6(X) 1
#else
#define sk_is_ipv4(X) 1
#define sk_is_ipv6(X) 0
#endif #endif
int sk_set_broadcast(sock *s, int enable);
static inline int int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */
sk_send_buffer_empty(sock *sk) int sk_join_group(sock *s, ip_addr maddr); /* Join multicast group on sk iface */
{ int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface */
return sk->tbuf == sk->tpos; 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 a, struct iface *ifa, char *passwd);
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);
extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */ extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */
/* Socket flags */ /* Socket flags */
#define SKF_V6ONLY 1 /* Use IPV6_V6ONLY socket option */ #define SKF_V4ONLY 0x01 /* Use IPv4 for IP sockets */
#define SKF_LADDR_RX 2 /* Report local address for RX packets */ #define SKF_V6ONLY 0x02 /* Use IPV6_V6ONLY socket option */
#define SKF_TTL_RX 4 /* Report TTL / Hop Limit for RX packets */ #define SKF_LADDR_RX 0x04 /* Report local address for RX packets */
#define SKF_BIND 8 /* Bind datagram socket to given source address */ #define SKF_TTL_RX 0x08 /* Report TTL / Hop Limit for RX packets */
#define SKF_BIND 0x10 /* Bind datagram socket to given source address */
#define SKF_THREAD 0x100 /* Socked used in thread, Do not add to main loop */ #define SKF_THREAD 0x100 /* Socked used in thread, Do not add to main loop */
#define SKF_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */ #define SKF_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */

View file

@ -101,8 +101,8 @@ bfd_rx_hook(sock *sk, int len)
uint err_val = 0; uint err_val = 0;
char fb[8]; char fb[8];
if ((sk->sport == BFD_CONTROL_PORT) && (sk->ttl < 255)) if ((sk->sport == BFD_CONTROL_PORT) && (sk->rcv_ttl < 255))
DROP("wrong TTL", sk->ttl); DROP("wrong TTL", sk->rcv_ttl);
if (len < BFD_BASE_LEN) if (len < BFD_BASE_LEN)
DROP("too short", len); DROP("too short", len);
@ -209,6 +209,7 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop)
return sk; return sk;
err: err:
sk_log_error(sk, p->p.name);
rfree(sk); rfree(sk);
return NULL; return NULL;
} }
@ -243,6 +244,7 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
return sk; return sk;
err: err:
sk_log_error(sk, p->p.name);
rfree(sk); rfree(sk);
return NULL; return NULL;
} }

View file

@ -106,14 +106,11 @@ bgp_open(struct bgp_proto *p)
struct config *cfg = p->cf->c.global; struct config *cfg = p->cf->c.global;
int errcode; int errcode;
bgp_counter++;
if (!bgp_listen_sk) if (!bgp_listen_sk)
bgp_listen_sk = bgp_setup_listen_sk(cfg->listen_bgp_addr, cfg->listen_bgp_port, cfg->listen_bgp_flags); bgp_listen_sk = bgp_setup_listen_sk(cfg->listen_bgp_addr, cfg->listen_bgp_port, cfg->listen_bgp_flags);
if (!bgp_listen_sk) if (!bgp_listen_sk)
{ {
bgp_counter--;
errcode = BEM_NO_SOCKET; errcode = BEM_NO_SOCKET;
goto err; goto err;
} }
@ -121,16 +118,16 @@ bgp_open(struct bgp_proto *p)
if (!bgp_linpool) if (!bgp_linpool)
bgp_linpool = lp_new(&root_pool, 4080); bgp_linpool = lp_new(&root_pool, 4080);
bgp_counter++;
if (p->cf->password) if (p->cf->password)
if (sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, p->cf->password) < 0)
{ {
int rv = sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, p->cf->password); sk_log_error(bgp_listen_sk, p->p.name);
if (rv < 0)
{
bgp_close(p, 0); bgp_close(p, 0);
errcode = BEM_INVALID_MD5; errcode = BEM_INVALID_MD5;
goto err; goto err;
} }
}
return 0; return 0;
@ -194,7 +191,8 @@ bgp_close(struct bgp_proto *p, int apply_md5)
bgp_counter--; bgp_counter--;
if (p->cf->password && apply_md5) if (p->cf->password && apply_md5)
sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, NULL); if (sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, NULL) < 0)
sk_log_error(bgp_listen_sk, p->p.name);
if (!bgp_counter) if (!bgp_counter)
{ {
@ -697,25 +695,21 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
bgp_conn_set_state(conn, BS_CONNECT); bgp_conn_set_state(conn, BS_CONNECT);
if (sk_open(s) < 0) if (sk_open(s) < 0)
{ goto err;
bgp_sock_err(s, 0);
return;
}
/* Set minimal receive TTL if needed */ /* Set minimal receive TTL if needed */
if (p->cf->ttl_security) if (p->cf->ttl_security)
{
DBG("Setting minimum received TTL to %d", 256 - hops);
if (sk_set_min_ttl(s, 256 - hops) < 0) if (sk_set_min_ttl(s, 256 - hops) < 0)
{ goto err;
log(L_ERR "TTL security configuration failed, closing session");
bgp_sock_err(s, 0);
return;
}
}
DBG("BGP: Waiting for connect success\n"); DBG("BGP: Waiting for connect success\n");
bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time); bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
return;
err:
sk_log_error(s, p->p.name);
bgp_sock_err(s, 0);
return;
} }
/** /**
@ -760,32 +754,33 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
sk->dport, acc ? "accepted" : "rejected"); sk->dport, acc ? "accepted" : "rejected");
if (!acc) if (!acc)
goto err; goto reject;
int hops = p->cf->multihop ? : 1; int hops = p->cf->multihop ? : 1;
if (p->cf->ttl_security)
{ if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0)
/* TTL security support */ goto err;
if ((sk_set_ttl(sk, 255) < 0) ||
(sk_set_min_ttl(sk, 256 - hops) < 0)) if (p->cf->ttl_security)
{ if (sk_set_min_ttl(sk, 256 - hops) < 0)
log(L_ERR "TTL security configuration failed, closing session");
goto err; goto err;
}
}
else
sk_set_ttl(sk, hops);
bgp_setup_conn(p, &p->incoming_conn); bgp_setup_conn(p, &p->incoming_conn);
bgp_setup_sk(&p->incoming_conn, sk); bgp_setup_sk(&p->incoming_conn, sk);
bgp_send_open(&p->incoming_conn); bgp_send_open(&p->incoming_conn);
return 0; return 0;
err:
sk_log_error(sk, p->p.name);
log(L_ERR "%s: Incoming connection aborted", p->p.name);
rfree(sk);
return 0;
} }
} }
log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)", log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport); sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport);
err: reject:
rfree(sk); rfree(sk);
return 0; return 0;
} }
@ -816,13 +811,15 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags)
s->err_hook = bgp_listen_sock_err; s->err_hook = bgp_listen_sock_err;
if (sk_open(s) < 0) if (sk_open(s) < 0)
{ goto err;
log(L_ERR "BGP: Unable to open listening socket");
rfree(s);
return NULL;
}
return s; return s;
err:
sk_log_error(s, "BGP");
log(L_ERR "BGP: Cannot open listening socket");
rfree(s);
return NULL;
} }
static void static void

View file

@ -90,6 +90,8 @@ find_nbma_node_in(list *nnl, ip_addr ip)
static int static int
ospf_sk_open(struct ospf_iface *ifa) ospf_sk_open(struct ospf_iface *ifa)
{ {
struct proto_ospf *po = ifa->oa->po;
sock *sk = sk_new(ifa->pool); sock *sk = sk_new(ifa->pool);
sk->type = SK_IP; sk->type = SK_IP;
sk->dport = OSPF_PROTO; sk->dport = OSPF_PROTO;
@ -121,7 +123,7 @@ ospf_sk_open(struct ospf_iface *ifa)
{ {
ifa->all_routers = ifa->addr->brd; ifa->all_routers = ifa->addr->brd;
if (sk_set_broadcast(sk, 1) < 0) if (sk_setup_broadcast(sk) < 0)
goto err; goto err;
} }
else else
@ -141,6 +143,7 @@ ospf_sk_open(struct ospf_iface *ifa)
return 1; return 1;
err: err:
sk_log_error(sk, po->proto.name);
rfree(sk); rfree(sk);
return 0; return 0;
} }
@ -151,7 +154,9 @@ ospf_sk_join_dr(struct ospf_iface *ifa)
if (ifa->sk_dr) if (ifa->sk_dr)
return; return;
sk_join_group(ifa->sk, AllDRouters); if (sk_join_group(ifa->sk, AllDRouters) < 0)
sk_log_error(ifa->sk, ifa->oa->po->proto.name);
ifa->sk_dr = 1; ifa->sk_dr = 1;
} }
@ -161,15 +166,15 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
if (!ifa->sk_dr) if (!ifa->sk_dr)
return; return;
sk_leave_group(ifa->sk, AllDRouters); if (sk_leave_group(ifa->sk, AllDRouters) < 0)
sk_log_error(ifa->sk, ifa->oa->po->proto.name);
ifa->sk_dr = 0; ifa->sk_dr = 0;
} }
void void
ospf_open_vlink_sk(struct proto_ospf *po) ospf_open_vlink_sk(struct proto_ospf *po)
{ {
struct proto *p = &po->proto;
sock *sk = sk_new(po->proto.pool); sock *sk = sk_new(po->proto.pool);
sk->type = SK_IP; sk->type = SK_IP;
sk->dport = OSPF_PROTO; sk->dport = OSPF_PROTO;
@ -197,8 +202,9 @@ ospf_open_vlink_sk(struct proto_ospf *po)
return; return;
err: err:
sk_log_error(sk, po->proto.name);
log(L_ERR "%s: Cannot open virtual link socket", po->proto.name);
rfree(sk); rfree(sk);
log(L_ERR "%s: Cannot open virtual link socket", p->name);
} }
static void static void
@ -463,7 +469,7 @@ ospf_iface_add(struct object_lock *lock)
/* Open socket if interface is not stub */ /* Open socket if interface is not stub */
if (! ifa->stub && ! ospf_sk_open(ifa)) if (! ifa->stub && ! ospf_sk_open(ifa))
{ {
log(L_ERR "%s: Socket open failed on interface %s, declaring as stub", p->name, ifa->ifname); log(L_ERR "%s: Cannot open socket for %s, declaring as stub", p->name, ifa->ifname);
ifa->ioprob = OSPF_I_SK; ifa->ioprob = OSPF_I_SK;
ifa->stub = 1; ifa->stub = 1;
} }

View file

@ -308,9 +308,9 @@ ospf_rx_hook(sock *sk, int size)
return 1; return 1;
} }
if (ifa->check_ttl && (sk->ttl < 255)) if (ifa->check_ttl && (sk->rcv_ttl < 255))
{ {
log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->ttl); log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->rcv_ttl);
return 1; return 1;
} }

View file

@ -416,11 +416,11 @@ radv_sk_open(struct radv_iface *ifa)
sk->data = ifa; sk->data = ifa;
sk->flags = SKF_LADDR_RX; sk->flags = SKF_LADDR_RX;
if (sk_open(sk) != 0) if (sk_open(sk) < 0)
goto err; goto err;
/* We want listen just to ICMPv6 messages of type RS and RA */ /* We want listen just to ICMPv6 messages of type RS and RA */
if (sk_set_icmp_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0) if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0)
goto err; goto err;
if (sk_setup_multicast(sk) < 0) if (sk_setup_multicast(sk) < 0)
@ -433,6 +433,7 @@ radv_sk_open(struct radv_iface *ifa)
return 1; return 1;
err: err:
sk_log_error(sk, ifa->ra->p.name);
rfree(sk); rfree(sk);
return 0; return 0;
} }

View file

@ -483,10 +483,10 @@ rip_rx(sock *s, int size)
iface = i->iface; iface = i->iface;
#endif #endif
if (i->check_ttl && (s->ttl < 255)) if (i->check_ttl && (s->rcv_ttl < 255))
{ {
log( L_REMOTE "%s: Discarding packet with TTL %d (< 255) from %I on %s", log( L_REMOTE "%s: Discarding packet with TTL %d (< 255) from %I on %s",
p->name, s->ttl, s->faddr, i->iface->name); p->name, s->rcv_ttl, s->faddr, i->iface->name);
return 1; return 1;
} }
@ -733,7 +733,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
log( L_WARN "%s: interface %s is too strange for me", p->name, rif->iface->name ); log( L_WARN "%s: interface %s is too strange for me", p->name, rif->iface->name );
} else { } else {
if (sk_open(rif->sock)<0) if (sk_open(rif->sock) < 0)
goto err; goto err;
if (rif->multicast) if (rif->multicast)
@ -745,7 +745,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
} }
else else
{ {
if (sk_set_broadcast(rif->sock, 1) < 0) if (sk_setup_broadcast(rif->sock) < 0)
goto err; goto err;
} }
} }
@ -755,7 +755,8 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
return rif; return rif;
err: err:
log( L_ERR "%s: could not create socket for %s", p->name, rif->iface ? rif->iface->name : "(dummy)" ); sk_log_error(rif->sock, p->name);
log(L_ERR "%s: Cannot open socket for %s", p->name, rif->iface ? rif->iface->name : "(dummy)" );
if (rif->iface) { if (rif->iface) {
rfree(rif->sock); rfree(rif->sock);
mb_free(rif); mb_free(rif);

View file

@ -251,9 +251,9 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
_I0(gw) = 0xfe800000 | (i->index & 0x0000ffff); _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
#endif #endif
fill_in_sockaddr(&dst, net->n.prefix, NULL, 0); sockaddr_fill(&dst, BIRD_AF, net->n.prefix, NULL, 0);
fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), NULL, 0); sockaddr_fill(&mask, BIRD_AF, ipa_mkmask(net->n.pxlen), NULL, 0);
fill_in_sockaddr(&gate, gw, NULL, 0); sockaddr_fill(&gate, BIRD_AF, gw, NULL, 0);
switch (a->dest) switch (a->dest)
{ {
@ -280,7 +280,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
return -1; return -1;
} }
fill_in_sockaddr(&gate, i->addr->ip, NULL, 0); sockaddr_fill(&dst, BIRD_AF, i->addr->ip, NULL, 0);
msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_addrs |= RTA_GATEWAY;
} }
break; break;
@ -366,20 +366,16 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
GETADDR(&gate, RTA_GATEWAY); GETADDR(&gate, RTA_GATEWAY);
GETADDR(&mask, RTA_NETMASK); GETADDR(&mask, RTA_NETMASK);
if (sa_family_check(&dst)) if (dst.sa.sa_family != BIRD_AF)
get_sockaddr(&dst, &idst, NULL, NULL, 0);
else
SKIP("invalid DST"); SKIP("invalid DST");
/* We will check later whether we have valid gateway addr */ idst = ipa_from_sa(&dst);
if (sa_family_check(&gate)) imask = ipa_from_sa(&mask);
get_sockaddr(&gate, &igate, NULL, NULL, 0); igate = (gate.sa.sa_family == BIRD_AF) ? ipa_from_sa(&gate) : IPA_NONE;
else
igate = IPA_NONE;
/* We do not test family for RTA_NETMASK, because BSD sends us /* We do not test family for RTA_NETMASK, because BSD sends us
some strange values, but interpreting them as IPv4/IPv6 works */ some strange values, but interpreting them as IPv4/IPv6 works */
get_sockaddr(&mask, &imask, NULL, NULL, 0);
int c = ipa_classify_net(idst); int c = ipa_classify_net(idst);
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
@ -648,12 +644,13 @@ krt_read_addr(struct ks_msg *msg, int scan)
GETADDR (&brd, RTA_BRD); GETADDR (&brd, RTA_BRD);
/* Some other family address */ /* Some other family address */
if (!sa_family_check(&addr)) if (addr.sa.sa_family != BIRD_AF)
return; return;
get_sockaddr(&addr, &iaddr, NULL, NULL, 0); iaddr = ipa_from_sa(&addr);
get_sockaddr(&mask, &imask, NULL, NULL, 0); imask = ipa_from_sa(&mask);
get_sockaddr(&brd, &ibrd, NULL, NULL, 0); ibrd = ipa_from_sa(&brd);
if ((masklen = ipa_mklen(imask)) < 0) if ((masklen = ipa_mklen(imask)) < 0)
{ {
@ -806,7 +803,7 @@ krt_sysctl_scan(struct proto *p, int cmd, int table_id)
mib[0] = CTL_NET; mib[0] = CTL_NET;
mib[1] = PF_ROUTE; mib[1] = PF_ROUTE;
mib[2] = 0; mib[2] = 0;
mib[3] = BIRD_PF; mib[3] = BIRD_AF;
mib[4] = cmd; mib[4] = cmd;
mib[5] = 0; mib[5] = 0;
mcnt = 6; mcnt = 6;

View file

@ -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> * (c) 2004 Ondrej Filip <feela@network.cz>
* *
* Can be freely distributed and used under the terms of the GNU GPL. * 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__ #ifdef __NetBSD__
#ifndef IP_RECVTTL #ifndef IP_RECVTTL
@ -22,173 +27,117 @@
#define TCP_MD5SIG TCP_SIGNATURE_ENABLE #define TCP_MD5SIG TCP_SIGNATURE_ENABLE
#endif #endif
#ifdef IPV6
static inline void #define SA_LEN(x) (x).sa.sa_len
set_inaddr(struct in6_addr * ia, ip_addr a)
/*
* BSD IPv4 multicast syscalls
*/
#define INIT_MREQ4(maddr,ifa) \
{ .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) }
static inline int
sk_setup_multicast4(sock *s)
{ {
ipa_hton(a); struct in_addr ifa = ipa_to_in4(s->iface->addr->ip);
memcpy(ia, &a, sizeof(a));
}
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 Multicast handling for IPv4 */
static inline char *
sysio_setup_multicast(sock *s)
{
struct in_addr m;
u8 zero = 0;
u8 ttl = s->ttl; u8 ttl = s->ttl;
u8 n = 0;
if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
return "IP_MULTICAST_LOOP";
if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
return "IP_MULTICAST_TTL";
/* This defines where should we send _outgoing_ multicasts */ /* This defines where should we send _outgoing_ multicasts */
set_inaddr(&m, s->iface->addr->ip); if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &ifa, sizeof(ifa)) < 0)
if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0) ERR("IP_MULTICAST_IF");
return "IP_MULTICAST_IF";
return NULL; if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
ERR("IP_MULTICAST_TTL");
if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0)
ERR("IP_MULTICAST_LOOP");
return 0;
}
static inline int
sk_join_group4(sock *s, ip_addr maddr)
{
struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)
ERR("IP_ADD_MEMBERSHIP");
return 0;
}
static inline int
sk_leave_group4(sock *s, ip_addr maddr)
{
struct ip_mreq mr = INIT_MREQ4(maddr, s->iface);
if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0)
ERR("IP_ADD_MEMBERSHIP");
return 0;
} }
static inline char * /*
sysio_join_group(sock *s, ip_addr maddr) * BSD IPv4 packet control messages
*/
/* It uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
#define CMSG4_SPACE_PKTINFO (CMSG_SPACE(sizeof(struct in_addr)) + \
CMSG_SPACE(sizeof(struct sockaddr_dl)))
#define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(char))
static inline int
sk_request_cmsg4_pktinfo(sock *s)
{ {
struct ip_mreq mreq; int y = 1;
bzero(&mreq, sizeof(mreq)); if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &y, sizeof(y)) < 0)
set_inaddr(&mreq.imr_interface, s->iface->addr->ip); ERR("IP_RECVDSTADDR");
set_inaddr(&mreq.imr_multiaddr, maddr);
/* And this one sets interface for _receiving_ multicasts from */ if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &y, sizeof(y)) < 0)
if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) ERR("IP_RECVIF");
return "IP_ADD_MEMBERSHIP";
return NULL; return 0;
} }
static inline char * static inline int
sysio_leave_group(sock *s, ip_addr maddr) sk_request_cmsg4_ttl(sock *s)
{ {
struct ip_mreq mreq; int y = 1;
bzero(&mreq, sizeof(mreq)); if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &y, sizeof(y)) < 0)
set_inaddr(&mreq.imr_interface, s->iface->addr->ip); ERR("IP_RECVTTL");
set_inaddr(&mreq.imr_multiaddr, maddr);
/* And this one sets interface for _receiving_ multicasts from */ return 0;
if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return "IP_DROP_MEMBERSHIP";
return NULL;
}
/* BSD RX/TX packet info handling for IPv4 */
/* it uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
#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))
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";
if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
return "IP_RECVIF";
}
if ((s->flags & SKF_TTL_RX) &&
(setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
return "IP_RECVTTL";
return NULL;
} }
static inline void static inline void
sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm)
{ {
struct cmsghdr *cm; if (cm->cmsg_type == IP_RECVDSTADDR)
struct in_addr *ra = NULL; s->laddr = ipa_from_in4(* (struct in_addr *) CMSG_DATA(cm));
struct sockaddr_dl *ri = NULL;
unsigned char *ttl = NULL;
for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) if (cm->cmsg_type == IP_RECVIF)
{ s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index;
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);
}
if (s->flags & SKF_LADDR_RX)
{
s->laddr = IPA_NONE;
s->lifindex = 0;
if (ra)
get_inaddr(&s->laddr, ra);
if (ri)
s->lifindex = ri->sdl_index;
}
if (s->flags & SKF_TTL_RX)
s->ttl = ttl ? *ttl : -1;
// log(L_WARN "RX %I %d", s->laddr, s->lifindex);
} }
/* 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 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 #ifdef IP_SENDSRCADDR
struct cmsghdr *cm; struct cmsghdr *cm;
struct in_addr *sa; 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)); cm->cmsg_len = CMSG_LEN(sizeof(*sa));
sa = (struct in_addr *) CMSG_DATA(cm); sa = (struct in_addr *) CMSG_DATA(cm);
set_inaddr(sa, s->saddr); *sa = ipa_to_in4(s->saddr);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = cm->cmsg_len;
#endif #endif
} }
static void 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; struct ip *ip = hdr;
@ -222,8 +170,8 @@ fill_ip_header(sock *s, void *hdr, int dlen)
ip->ip_len = 20 + dlen; ip->ip_len = 20 + dlen;
ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl; ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl;
ip->ip_p = s->dport; ip->ip_p = s->dport;
set_inaddr(&ip->ip_src, s->saddr); ip->ip_src = ipa_to_in4(s->saddr);
set_inaddr(&ip->ip_dst, s->daddr); ip->ip_dst = ipa_to_in4(s->daddr);
#ifdef __OpenBSD__ #ifdef __OpenBSD__
/* OpenBSD expects ip_len in network order, other BSDs expect host order */ /* 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
} }
#endif
/*
* Miscellaneous BSD socket syscalls
*/
#include <netinet/tcp.h>
#ifndef TCP_KEYLEN_MAX #ifndef TCP_KEYLEN_MAX
#define TCP_KEYLEN_MAX 80 #define TCP_KEYLEN_MAX 80
#endif #endif
@ -248,72 +197,69 @@ fill_ip_header(sock *s, void *hdr, int dlen)
* management. * management.
*/ */
static int int
sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd) sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
{ {
int enable = 0; int enable = 0;
if (passwd)
if (passwd && *passwd)
{ {
int len = strlen(passwd); int len = strlen(passwd);
enable = TCP_SIG_SPI;
enable = len ? TCP_SIG_SPI : 0;
if (len > TCP_KEYLEN_MAX) if (len > TCP_KEYLEN_MAX)
{ ERR_MSG("MD5 password too long");
log(L_ERR "MD5 password too long");
return -1;
}
} }
int rv = setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)); if (setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)) < 0)
if (rv < 0)
{ {
if (errno == ENOPROTOOPT) if (errno == ENOPROTOOPT)
log(L_ERR "Kernel does not support TCP MD5 signatures"); ERR_MSG("Kernel does not support TCP MD5 signatures");
else else
log(L_ERR "sk_set_md5_auth_int: setsockopt: %m"); ERR("TCP_MD5SIG");
}
return rv;
}
#ifndef IPV6
static 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");
else
log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
return -1;
} }
return 0; return 0;
} }
#else /* IPv6 */ static inline int
sk_set_min_ttl4(sock *s, int ttl)
static int
sk_set_min_ttl6(sock *s, int ttl)
{ {
log(L_ERR "IPv6 TTL security not supported"); if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
return -1; {
if (errno == ENOPROTOOPT)
ERR_MSG("Kernel does not support IPv4 TTL security");
else
ERR("IP_MINTTL");
}
return 0;
} }
#endif static inline int
sk_set_min_ttl6(sock *s, int ttl)
{
ERR_MSG("Kernel does not support IPv6 TTL security");
}
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; int sk_priority_control = -1;
static int static inline int
sk_set_priority(sock *s, int prio UNUSED) sk_set_priority(sock *s, int prio UNUSED)
{ {
log(L_WARN "Socket priority not supported"); ERR_MSG("Socket priority not supported");
return -1;
} }

View file

@ -104,9 +104,9 @@ nl_request_dump(int cmd)
req.nh.nlmsg_type = cmd; req.nh.nlmsg_type = cmd;
req.nh.nlmsg_len = sizeof(req); req.nh.nlmsg_len = sizeof(req);
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
/* Is it important which PF_* is used for link-level interface scan? /* Is it important which AF_* is used for link-level interface scan?
It seems that some information is available only when PF_INET is used. */ It seems that some information is available only when AF_INET is used. */
req.g.rtgen_family = (cmd == RTM_GETLINK) ? PF_INET : BIRD_PF; req.g.rtgen_family = (cmd == RTM_GETLINK) ? AF_INET : BIRD_AF;
nl_send(&nl_scan, &req.nh); nl_send(&nl_scan, &req.nh);
} }
@ -1069,7 +1069,7 @@ nl_open_async(void)
sk->type = SK_MAGIC; sk->type = SK_MAGIC;
sk->rx_hook = nl_async_hook; sk->rx_hook = nl_async_hook;
sk->fd = fd; sk->fd = fd;
if (sk_open(sk)) if (sk_open(sk) < 0)
bug("Netlink: sk_open failed"); bug("Netlink: sk_open failed");
} }

View file

@ -6,46 +6,6 @@
* Can be freely distributed and used under the terms of the GNU GPL. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
#include <net/if.h>
#ifdef IPV6
#ifndef IPV6_UNICAST_HOPS
/* Needed on glibc 2.0 systems */
#include <linux/in6.h>
#define CONFIG_IPV6_GLIBC_20
#endif
static inline void
set_inaddr(struct in6_addr *ia, ip_addr a)
{
ipa_hton(a);
memcpy(ia, &a, sizeof(a));
}
static inline void
get_inaddr(ip_addr *a, struct in6_addr *ia)
{
memcpy(a, ia, sizeof(*a));
ipa_ntoh(*a);
}
#else
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);
}
#ifndef HAVE_STRUCT_IP_MREQN #ifndef HAVE_STRUCT_IP_MREQN
/* Several versions of glibc don't define this structure, so we have to do it ourselves */ /* Several versions of glibc don't define this structure, so we have to do it ourselves */
@ -57,181 +17,140 @@ struct ip_mreqn
}; };
#endif #endif
#ifndef IP_MINTTL
static inline void fill_mreqn(struct ip_mreqn *m, ip_addr maddr, struct iface *ifa) #define IP_MINTTL 21
{
bzero(m, sizeof(*m));
m->imr_ifindex = ifa->index;
set_inaddr(&m->imr_multiaddr, maddr);
}
static inline char *
sysio_setup_multicast(sock *s)
{
struct ip_mreqn m;
int zero = 0;
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
return "IP_MULTICAST_LOOP";
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0)
return "IP_MULTICAST_TTL";
/* This defines where should we send _outgoing_ multicasts */
fill_mreqn(&m, IPA_NONE, s->iface);
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0)
return "IP_MULTICAST_IF";
return NULL;
}
static inline char *
sysio_join_group(sock *s, ip_addr maddr)
{
struct ip_mreqn m;
/* And this one sets interface for _receiving_ multicasts from */
fill_mreqn(&m, maddr, s->iface);
if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0)
return "IP_ADD_MEMBERSHIP";
return NULL;
}
static inline char *
sysio_leave_group(sock *s, ip_addr maddr)
{
struct ip_mreqn m;
/* And this one sets interface for _receiving_ multicasts from */
fill_mreqn(&m, maddr, s->iface);
if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0)
return "IP_DROP_MEMBERSHIP";
return NULL;
}
#endif #endif
#ifndef IPV6_TCLASS
#define IPV6_TCLASS 67
#endif
#ifndef IPV6_MINHOPCOUNT
#define IPV6_MINHOPCOUNT 73
#endif
/* For the case that we have older libc headers */
/* Copied from Linux kernel file include/linux/tcp.h */
#ifndef TCP_MD5SIG #ifndef TCP_MD5SIG
#define TCP_MD5SIG 14 #define TCP_MD5SIG 14
#define TCP_MD5SIG_MAXKEYLEN 80 #define TCP_MD5SIG_MAXKEYLEN 80
#include <linux/types.h>
struct tcp_md5sig { struct tcp_md5sig {
struct sockaddr_storage tcpm_addr; /* address associated */ struct sockaddr_storage tcpm_addr; /* address associated */
__u16 __tcpm_pad1; /* zero */ u16 __tcpm_pad1; /* zero */
__u16 tcpm_keylen; /* key length */ u16 tcpm_keylen; /* key length */
__u32 __tcpm_pad2; /* zero */ u32 __tcpm_pad2; /* zero */
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
}; };
#endif #endif
static int
sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd) /* Linux does not care if sa_len is larger than needed */
#define SA_LEN(x) sizeof(sockaddr)
/*
* Linux IPv4 multicast syscalls
*/
#define INIT_MREQ4(maddr,ifa) \
{ .imr_multiaddr = ipa_to_in4(maddr), .imr_ifindex = ifa->index }
static inline int
sk_setup_multicast4(sock *s)
{ {
struct tcp_md5sig md5; struct ip_mreqn mr = { .imr_ifindex = s->iface->index };
int ttl = s->ttl;
int n = 0;
memset(&md5, 0, sizeof(md5)); /* This defines where should we send _outgoing_ multicasts */
memcpy(&md5.tcpm_addr, (struct sockaddr *) sa, sizeof(*sa)); if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &mr, sizeof(mr)) < 0)
ERR("IP_MULTICAST_IF");
if (passwd) if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
{ ERR("IP_MULTICAST_TTL");
int len = strlen(passwd);
if (len > TCP_MD5SIG_MAXKEYLEN) if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0)
{ ERR("IP_MULTICAST_LOOP");
log(L_ERR "MD5 password too long");
return -1;
}
md5.tcpm_keylen = len; return 0;
memcpy(&md5.tcpm_key, passwd, len); }
}
int rv = setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)); static inline int
sk_join_group4(sock *s, ip_addr maddr)
{
struct ip_mreqn mr = INIT_MREQ4(maddr, s->iface);
if (rv < 0) if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)
{ ERR("IP_ADD_MEMBERSHIP");
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; return 0;
}
static inline int
sk_leave_group4(sock *s, ip_addr maddr)
{
struct ip_mreqn mr = INIT_MREQ4(maddr, s->iface);
if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0)
ERR("IP_DROP_MEMBERSHIP");
return 0;
} }
#ifndef IPV6 /*
* Linux IPv4 packet control messages
*/
/* RX/TX packet info handling for IPv4 */
/* Mostly similar to standardized IPv6 code */ /* Mostly similar to standardized IPv6 code */
#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int))) #define CMSG4_SPACE_PKTINFO CMSG_SPACE(sizeof(struct in_pktinfo))
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo)) #define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(int))
static char * static inline int
sysio_register_cmsgs(sock *s) sk_request_cmsg4_pktinfo(sock *s)
{ {
int ok = 1; int y = 1;
if ((s->flags & SKF_LADDR_RX) && if (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &y, sizeof(y)) < 0)
(setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)) ERR("IP_PKTINFO");
return "IP_PKTINFO";
if ((s->flags & SKF_TTL_RX) && return 0;
(setsockopt(s->fd, SOL_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
return "IP_RECVTTL";
return NULL;
} }
static void static inline int
sysio_process_rx_cmsgs(sock *s, struct msghdr *msg) sk_request_cmsg4_ttl(sock *s)
{ {
struct cmsghdr *cm; int y = 1;
struct in_pktinfo *pi = NULL;
int *ttl = NULL;
for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm)) if (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &y, sizeof(y)) < 0)
{ ERR("IP_RECVTTL");
if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO)
pi = (struct in_pktinfo *) CMSG_DATA(cm);
if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_TTL) return 0;
ttl = (int *) CMSG_DATA(cm); }
}
if (s->flags & SKF_LADDR_RX) static inline void
sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm)
{
if (cm->cmsg_type == IP_PKTINFO)
{ {
if (pi) struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cm);
{ s->laddr = ipa_from_in4(pi->ipi_addr);
get_inaddr(&s->laddr, &pi->ipi_addr);
s->lifindex = pi->ipi_ifindex; s->lifindex = pi->ipi_ifindex;
} }
else
{
s->laddr = IPA_NONE;
s->lifindex = 0;
}
}
if (s->flags & SKF_TTL_RX)
s->ttl = ttl ? *ttl : -1;
return;
} }
static void static inline void
sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
{
if (cm->cmsg_type == IP_TTL)
s->rcv_ttl = * (int *) CMSG_DATA(cm);
}
static inline void
sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{ {
struct cmsghdr *cm; struct cmsghdr *cm;
struct in_pktinfo *pi; struct in_pktinfo *pi;
@ -246,78 +165,105 @@ sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
pi = (struct in_pktinfo *) CMSG_DATA(cm); pi = (struct in_pktinfo *) CMSG_DATA(cm);
pi->ipi_ifindex = s->iface ? s->iface->index : 0; pi->ipi_ifindex = s->iface ? s->iface->index : 0;
set_inaddr(&pi->ipi_spec_dst, s->saddr); pi->ipi_spec_dst = ipa_to_in4(s->saddr);
set_inaddr(&pi->ipi_addr, IPA_NONE); pi->ipi_addr = ipa_to_in4(IPA_NONE);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = cm->cmsg_len;
} }
#endif /*
* Miscellaneous Linux socket syscalls
*/
int
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
{
struct tcp_md5sig md5;
#ifndef IP_MINTTL memset(&md5, 0, sizeof(md5));
#define IP_MINTTL 21 sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, a, ifa, 0);
#endif
#ifndef IPV6_MINHOPCOUNT if (passwd)
#define IPV6_MINHOPCOUNT 73 {
#endif int len = strlen(passwd);
if (len > TCP_MD5SIG_MAXKEYLEN)
ERR_MSG("MD5 password too long");
#ifndef IPV6 md5.tcpm_keylen = len;
memcpy(&md5.tcpm_key, passwd, len);
}
static int 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");
}
return 0;
}
static inline int
sk_set_min_ttl4(sock *s, int ttl) sk_set_min_ttl4(sock *s, int ttl)
{ {
if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
{ {
if (errno == ENOPROTOOPT) if (errno == ENOPROTOOPT)
log(L_ERR "Kernel does not support IPv4 TTL security"); ERR_MSG("Kernel does not support IPv4 TTL security");
else else
log(L_ERR "sk_set_min_ttl4: setsockopt: %m"); ERR("IP_MINTTL");
return -1;
} }
return 0; return 0;
} }
#else static inline int
static int
sk_set_min_ttl6(sock *s, int ttl) sk_set_min_ttl6(sock *s, int ttl)
{ {
if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0) if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0)
{ {
if (errno == ENOPROTOOPT) if (errno == ENOPROTOOPT)
log(L_ERR "Kernel does not support IPv6 TTL security"); ERR_MSG("Kernel does not support IPv6 TTL security");
else else
log(L_ERR "sk_set_min_ttl6: setsockopt: %m"); ERR("IPV6_MINHOPCOUNT");
return -1;
} }
return 0; return 0;
} }
#endif static inline int
sk_disable_mtu_disc4(sock *s)
{
int dont = IP_PMTUDISC_DONT;
if (setsockopt(s->fd, SOL_IP, IP_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
ERR("IP_MTU_DISCOVER");
#ifndef IPV6_TCLASS return 0;
#define IPV6_TCLASS 67 }
#endif
static inline int
sk_disable_mtu_disc6(sock *s)
{
int dont = IPV6_PMTUDISC_DONT;
if (setsockopt(s->fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
ERR("IPV6_MTU_DISCOVER");
return 0;
}
int sk_priority_control = 7; int sk_priority_control = 7;
static int static inline int
sk_set_priority(sock *s, int prio) sk_set_priority(sock *s, int prio)
{ {
if (setsockopt(s->fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0) if (setsockopt(s->fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0)
{ ERR("SO_PRIORITY");
log(L_WARN "sk_set_priority: setsockopt: %m");
return -1;
}
return 0; return 0;
} }

File diff suppressed because it is too large Load diff

View file

@ -463,7 +463,12 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
s->type = SK_UNIX_PASSIVE; s->type = SK_UNIX_PASSIVE;
s->rx_hook = cli_connect; s->rx_hook = cli_connect;
s->rbsize = 1024; s->rbsize = 1024;
sk_open_unix(s, path_control_socket);
/* Return value intentionally ignored */
unlink(path_control_socket);
if (sk_open_unix(s, path_control_socket) < 0)
die("Cannot create control socket %s: %m", path_control_socket);
if (use_uid || use_gid) if (use_uid || use_gid)
if (chown(path_control_socket, use_uid, use_gid) < 0) if (chown(path_control_socket, use_uid, use_gid) < 0)

View file

@ -12,6 +12,8 @@
#include <sys/socket.h> #include <sys/socket.h>
struct pool; struct pool;
struct iface;
struct birdsock;
/* main.c */ /* main.c */
@ -27,36 +29,81 @@ void cmd_shutdown(void);
#define UNIX_DEFAULT_CONFIGURE_TIMEOUT 300 #define UNIX_DEFAULT_CONFIGURE_TIMEOUT 300
/* io.c */ /* io.c */
volatile int async_config_flag; #define ERR(c) do { s->err = c; return -1; } while (0)
volatile int async_dump_flag; #define ERR2(c) do { s->err = c; goto err; } while (0)
volatile int async_shutdown_flag; #define ERR_MSG(c) do { errno = 0; s->err = c; return -1; } while (0)
#define SOCKADDR_SIZE 32
typedef struct sockaddr_bird {
struct sockaddr sa;
char padding[SOCKADDR_SIZE - sizeof(struct sockaddr)];
} sockaddr;
#ifdef IPV6 #ifdef IPV6
#define BIRD_PF PF_INET6
#define BIRD_AF AF_INET6 #define BIRD_AF AF_INET6
typedef struct sockaddr_in6 sockaddr; #define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4)
static inline int sa_family_check(sockaddr *sa) { return sa->sin6_family == AF_INET6; } #define ipa_is_link_local(x) ipa_has_link_scope(x)
#define ipa_from_sa(x) ipa_from_sa6(x)
#define ipa_from_u32(x) _MI6(0,0,0xffff,x)
#define ipa_to_u32(x) _I3(x)
#else #else
#define BIRD_PF PF_INET
#define BIRD_AF AF_INET #define BIRD_AF AF_INET
typedef struct sockaddr_in sockaddr; #define _I0(X) 0
static inline int sa_family_check(sockaddr *sa) { return sa->sin_family == AF_INET; } #define _I1(X) 0
#define _I2(X) 0
#define _I3(X) 0
#define _MI6(x1,x2,x3,x4) IPA_NONE
#define ipa_is_link_local(x) 0
#define ipa_from_sa(x) ipa_from_sa4(x)
#endif #endif
/* This is sloppy hack, it should be detected by configure script */
/* Linux systems have it defined so this is definition for BSD systems */
#ifndef s6_addr32
#define s6_addr32 __u6_addr.__u6_addr32
#endif
static inline ip_addr ipa_from_in4(struct in_addr a)
{ return ipa_from_u32(ntohl(a.s_addr)); }
static inline ip_addr ipa_from_in6(struct in6_addr a)
{ return _MI6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); }
static inline ip_addr ipa_from_sa4(sockaddr *sa)
{ return ipa_from_in4(((struct sockaddr_in *) sa)->sin_addr); }
static inline ip_addr ipa_from_sa6(sockaddr *sa)
{ return ipa_from_in6(((struct sockaddr_in6 *) sa)->sin6_addr); }
static inline struct in_addr ipa_to_in4(ip_addr a)
{ return (struct in_addr) { htonl(ipa_to_u32(a)) }; }
static inline struct in6_addr ipa_to_in6(ip_addr a)
{ return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; }
void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port);
int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port);
#ifndef SUN_LEN #ifndef SUN_LEN
#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path)) #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path))
#endif #endif
struct birdsock; volatile int async_config_flag;
struct iface; volatile int async_dump_flag;
volatile int async_shutdown_flag;
void io_init(void); void io_init(void);
void io_loop(void); void io_loop(void);
void fill_in_sockaddr(sockaddr *sa, ip_addr a, struct iface *ifa, unsigned port); int sk_open_unix(struct birdsock *s, char *name);
void get_sockaddr(sockaddr *sa, ip_addr *a, struct iface **ifa, unsigned *port, int check);
void sk_open_unix(struct birdsock *s, char *name);
void *tracked_fopen(struct pool *, char *name, char *mode); void *tracked_fopen(struct pool *, char *name, char *mode);
void test_old_bird(char *path); void test_old_bird(char *path);