Commit 05476c4d authored by Ondřej Zajíček's avatar Ondřej Zajíček
Browse files

IPv4/IPv6 integrated socket code.

parent 1149aa97
......@@ -19,7 +19,6 @@
#include "lib/resource.h"
#include "lib/string.h"
#include "client/client.h"
#include "sysdep/unix/unix.h"
static int input_hidden_end;
static int prompt_active;
......
......@@ -221,6 +221,16 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
continue;
case 'm':
if (flags & SPECIAL) {
if (!errno)
continue;
if (size < 2)
return -1;
*str++ = ':';
*str++ = ' ';
start += 2;
size -= 2;
}
s = strerror(errno);
goto str;
case 'M':
......
......@@ -10,6 +10,7 @@
#define _BIRD_SOCKET_H_
#include <errno.h>
// #include <sys/socket.h>
#include "lib/resource.h"
......@@ -43,17 +44,21 @@ typedef struct birdsock {
unsigned lifindex; /* local interface that received the datagram */
/* 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 index; /* Index in poll buffer */
int rcv_ttl; /* TTL of last received datagram */
node n;
void *rbuf_alloc, *tbuf_alloc;
char *password; /* Password for MD5 authentication */
char *password; /* Password for MD5 authentication */
char *err; /* Error message */
} sock;
sock *sock_new(pool *); /* Allocate new socket */
#define sk_new(X) sock_new(X) /* Wrapper to avoid name collision with OpenSSL */
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_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */
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_tbuf(sock *s, void *tbuf); /* Switch TX buffer, NULL-> return to internal */
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 */
int sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd);
int sk_rx_ready(sock *s);
static inline int sk_send_buffer_empty(sock *sk)
{ return sk->tbuf == sk->tpos; }
/* 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
int sk_set_ipv6_checksum(sock *s, int offset);
int sk_set_icmp_filter(sock *s, int p1, int p2);
#define sk_is_ipv4(X) 0
#define sk_is_ipv6(X) 1
#else
#define sk_is_ipv4(X) 1
#define sk_is_ipv6(X) 0
#endif
int sk_set_broadcast(sock *s, int enable);
static inline int
sk_send_buffer_empty(sock *sk)
{
return sk->tbuf == sk->tpos;
}
int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */
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 */
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 */
#define SKF_V6ONLY 1 /* Use IPV6_V6ONLY socket option */
#define SKF_LADDR_RX 2 /* Report local address for RX packets */
#define SKF_TTL_RX 4 /* Report TTL / Hop Limit for RX packets */
#define SKF_BIND 8 /* Bind datagram socket to given source address */
#define SKF_V4ONLY 0x01 /* Use IPv4 for IP sockets */
#define SKF_V6ONLY 0x02 /* Use IPV6_V6ONLY socket option */
#define SKF_LADDR_RX 0x04 /* Report local address for RX packets */
#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_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */
......
......@@ -101,8 +101,8 @@ bfd_rx_hook(sock *sk, int len)
uint err_val = 0;
char fb[8];
if ((sk->sport == BFD_CONTROL_PORT) && (sk->ttl < 255))
DROP("wrong TTL", sk->ttl);
if ((sk->sport == BFD_CONTROL_PORT) && (sk->rcv_ttl < 255))
DROP("wrong TTL", sk->rcv_ttl);
if (len < BFD_BASE_LEN)
DROP("too short", len);
......@@ -209,6 +209,7 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop)
return sk;
err:
sk_log_error(sk, p->p.name);
rfree(sk);
return NULL;
}
......@@ -243,6 +244,7 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
return sk;
err:
sk_log_error(sk, p->p.name);
rfree(sk);
return NULL;
}
......@@ -106,14 +106,11 @@ bgp_open(struct bgp_proto *p)
struct config *cfg = p->cf->c.global;
int errcode;
bgp_counter++;
if (!bgp_listen_sk)
bgp_listen_sk = bgp_setup_listen_sk(cfg->listen_bgp_addr, cfg->listen_bgp_port, cfg->listen_bgp_flags);
if (!bgp_listen_sk)
{
bgp_counter--;
errcode = BEM_NO_SOCKET;
goto err;
}
......@@ -121,16 +118,16 @@ bgp_open(struct bgp_proto *p)
if (!bgp_linpool)
bgp_linpool = lp_new(&root_pool, 4080);
bgp_counter++;
if (p->cf->password)
{
int rv = sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, p->cf->password);
if (rv < 0)
{
bgp_close(p, 0);
errcode = BEM_INVALID_MD5;
goto err;
}
}
if (sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, p->cf->password) < 0)
{
sk_log_error(bgp_listen_sk, p->p.name);
bgp_close(p, 0);
errcode = BEM_INVALID_MD5;
goto err;
}
return 0;
......@@ -194,7 +191,8 @@ bgp_close(struct bgp_proto *p, int apply_md5)
bgp_counter--;
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)
{
......@@ -697,25 +695,21 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
bgp_conn_set_state(conn, BS_CONNECT);
if (sk_open(s) < 0)
{
bgp_sock_err(s, 0);
return;
}
goto err;
/* Set minimal receive TTL if needed */
if (p->cf->ttl_security)
{
DBG("Setting minimum received TTL to %d", 256 - hops);
if (sk_set_min_ttl(s, 256 - hops) < 0)
{
log(L_ERR "TTL security configuration failed, closing session");
bgp_sock_err(s, 0);
return;
}
}
goto err;
DBG("BGP: Waiting for connect success\n");
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");
if (!acc)
goto err;
goto reject;
int hops = p->cf->multihop ? : 1;
if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0)
goto err;
if (p->cf->ttl_security)
{
/* TTL security support */
if ((sk_set_ttl(sk, 255) < 0) ||
(sk_set_min_ttl(sk, 256 - hops) < 0))
{
log(L_ERR "TTL security configuration failed, closing session");
if (sk_set_min_ttl(sk, 256 - hops) < 0)
goto err;
}
}
else
sk_set_ttl(sk, hops);
bgp_setup_conn(p, &p->incoming_conn);
bgp_setup_sk(&p->incoming_conn, sk);
bgp_send_open(&p->incoming_conn);
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)",
sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport);
err:
reject:
rfree(sk);
return 0;
}
......@@ -816,13 +811,15 @@ bgp_setup_listen_sk(ip_addr addr, unsigned port, u32 flags)
s->err_hook = bgp_listen_sock_err;
if (sk_open(s) < 0)
{
log(L_ERR "BGP: Unable to open listening socket");
rfree(s);
return NULL;
}
goto err;
return s;
err:
sk_log_error(s, "BGP");
log(L_ERR "BGP: Cannot open listening socket");
rfree(s);
return NULL;
}
static void
......
......@@ -90,6 +90,8 @@ find_nbma_node_in(list *nnl, ip_addr ip)
static int
ospf_sk_open(struct ospf_iface *ifa)
{
struct proto_ospf *po = ifa->oa->po;
sock *sk = sk_new(ifa->pool);
sk->type = SK_IP;
sk->dport = OSPF_PROTO;
......@@ -121,7 +123,7 @@ ospf_sk_open(struct ospf_iface *ifa)
{
ifa->all_routers = ifa->addr->brd;
if (sk_set_broadcast(sk, 1) < 0)
if (sk_setup_broadcast(sk) < 0)
goto err;
}
else
......@@ -141,6 +143,7 @@ ospf_sk_open(struct ospf_iface *ifa)
return 1;
err:
sk_log_error(sk, po->proto.name);
rfree(sk);
return 0;
}
......@@ -151,7 +154,9 @@ ospf_sk_join_dr(struct ospf_iface *ifa)
if (ifa->sk_dr)
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;
}
......@@ -161,15 +166,15 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
if (!ifa->sk_dr)
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;
}
void
ospf_open_vlink_sk(struct proto_ospf *po)
{
struct proto *p = &po->proto;
sock *sk = sk_new(po->proto.pool);
sk->type = SK_IP;
sk->dport = OSPF_PROTO;
......@@ -197,8 +202,9 @@ ospf_open_vlink_sk(struct proto_ospf *po)
return;
err:
sk_log_error(sk, po->proto.name);
log(L_ERR "%s: Cannot open virtual link socket", po->proto.name);
rfree(sk);
log(L_ERR "%s: Cannot open virtual link socket", p->name);
}
static void
......@@ -463,7 +469,7 @@ ospf_iface_add(struct object_lock *lock)
/* Open socket if interface is not stub */
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->stub = 1;
}
......
......@@ -308,9 +308,9 @@ ospf_rx_hook(sock *sk, int size)
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;
}
......
......@@ -416,11 +416,11 @@ radv_sk_open(struct radv_iface *ifa)
sk->data = ifa;
sk->flags = SKF_LADDR_RX;
if (sk_open(sk) != 0)
if (sk_open(sk) < 0)
goto err;
/* 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;
if (sk_setup_multicast(sk) < 0)
......@@ -433,6 +433,7 @@ radv_sk_open(struct radv_iface *ifa)
return 1;
err:
sk_log_error(sk, ifa->ra->p.name);
rfree(sk);
return 0;
}
......
......@@ -483,10 +483,10 @@ rip_rx(sock *s, int size)
iface = i->iface;
#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",
p->name, s->ttl, s->faddr, i->iface->name);
p->name, s->rcv_ttl, s->faddr, i->iface->name);
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 );
} else {
if (sk_open(rif->sock)<0)
if (sk_open(rif->sock) < 0)
goto err;
if (rif->multicast)
......@@ -745,7 +745,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
}
else
{
if (sk_set_broadcast(rif->sock, 1) < 0)
if (sk_setup_broadcast(rif->sock) < 0)
goto err;
}
}
......@@ -755,7 +755,8 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
return rif;
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) {
rfree(rif->sock);
mb_free(rif);
......
......@@ -251,9 +251,9 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
_I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
#endif
fill_in_sockaddr(&dst, net->n.prefix, NULL, 0);
fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), NULL, 0);
fill_in_sockaddr(&gate, gw, NULL, 0);
sockaddr_fill(&dst, BIRD_AF, net->n.prefix, NULL, 0);
sockaddr_fill(&mask, BIRD_AF, ipa_mkmask(net->n.pxlen), NULL, 0);
sockaddr_fill(&gate, BIRD_AF, gw, NULL, 0);
switch (a->dest)
{
......@@ -280,7 +280,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
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;
}
break;
......@@ -366,20 +366,16 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
GETADDR(&gate, RTA_GATEWAY);
GETADDR(&mask, RTA_NETMASK);
if (sa_family_check(&dst))
get_sockaddr(&dst, &idst, NULL, NULL, 0);
else
if (dst.sa.sa_family != BIRD_AF)
SKIP("invalid DST");
/* We will check later whether we have valid gateway addr */
if (sa_family_check(&gate))
get_sockaddr(&gate, &igate, NULL, NULL, 0);
else
igate = IPA_NONE;
idst = ipa_from_sa(&dst);
imask = ipa_from_sa(&mask);
igate = (gate.sa.sa_family == BIRD_AF) ? ipa_from_sa(&gate) : IPA_NONE;
/* We do not test family for RTA_NETMASK, because BSD sends us
some strange values, but interpreting them as IPv4/IPv6 works */
get_sockaddr(&mask, &imask, NULL, NULL, 0);
int c = ipa_classify_net(idst);
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);
/* Some other family address */
if (!sa_family_check(&addr))
if (addr.sa.sa_family != BIRD_AF)
return;
get_sockaddr(&addr, &iaddr, NULL, NULL, 0);
get_sockaddr(&mask, &imask, NULL, NULL, 0);
get_sockaddr(&brd, &ibrd, NULL, NULL, 0);
iaddr = ipa_from_sa(&addr);
imask = ipa_from_sa(&mask);
ibrd = ipa_from_sa(&brd);
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[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = BIRD_PF;
mib[3] = BIRD_AF;
mib[4] = cmd;
mib[5] = 0;
mcnt = 6;
......
/*
* 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;
}