IO: Minor changes in socket AF handing
AF can be specified implicitly by saddr or daddr, flags SKF_V4ONLY and SKF_V6ONLY are to be removed.
This commit is contained in:
parent
5af7b59660
commit
08b3a24da5
10 changed files with 91 additions and 77 deletions
46
lib/socket.h
46
lib/socket.h
|
@ -17,6 +17,7 @@ typedef struct birdsock {
|
|||
resource r;
|
||||
pool *pool; /* Pool where incoming connections should be allocated (for SK_xxx_PASSIVE) */
|
||||
int type; /* Socket type */
|
||||
int subtype; /* Socket subtype */
|
||||
void *data; /* User data */
|
||||
ip_addr saddr, daddr; /* IPA_NONE = unspecified */
|
||||
uint sport, dport; /* 0 = unspecified (for IP: protocol type) */
|
||||
|
@ -44,7 +45,7 @@ typedef struct birdsock {
|
|||
uint lifindex; /* local interface that received the datagram */
|
||||
/* laddr and lifindex are valid only if SKF_LADDR_RX flag is set to request it */
|
||||
|
||||
int fam; /* Address family (SK_FAM_* or 0 for non-IP) of fd */
|
||||
int af; /* System-dependend adress family (e.g. AF_INET) */
|
||||
int fd; /* System-dependent data */
|
||||
int index; /* Index in poll buffer */
|
||||
int rcv_ttl; /* TTL of last received datagram */
|
||||
|
@ -91,7 +92,6 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
|
|||
|
||||
/* Socket flags */
|
||||
|
||||
#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 */
|
||||
|
@ -116,31 +116,35 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
|
|||
#define SK_UNIX_PASSIVE 8
|
||||
#define SK_UNIX 9
|
||||
|
||||
/* Socket families */
|
||||
/*
|
||||
* Socket subtypes
|
||||
*/
|
||||
|
||||
#define SK_FAM_NONE 0
|
||||
#define SK_FAM_IPV4 4
|
||||
#define SK_FAM_IPV6 6
|
||||
#define SK_IPV4 1
|
||||
#define SK_IPV6 2
|
||||
|
||||
/*
|
||||
* For SK_UDP or SK_IP sockets setting DA/DP allows to use sk_send(),
|
||||
* otherwise sk_send_to() must be used.
|
||||
* For TCP/IP sockets, Address family (IPv4 or IPv6) can be specified either
|
||||
* explicitly (SK_IPV4 or SK_IPV6) or implicitly (based on saddr, daddr). But
|
||||
* these specifications must be consistent.
|
||||
*
|
||||
* For SK_IP sockets setting DP specifies protocol number, which is used
|
||||
* for both receiving and sending.
|
||||
* For SK_UDP or SK_IP sockets setting DA/DP allows to use sk_send(), otherwise
|
||||
* sk_send_to() must be used.
|
||||
*
|
||||
* For multicast on SK_UDP or SK_IP sockets set IF and TTL,
|
||||
* call sk_setup_multicast() to enable multicast on that socket,
|
||||
* and then use sk_join_group() and sk_leave_group() to manage
|
||||
* a set of received multicast groups.
|
||||
* For SK_IP sockets setting DP specifies protocol number, which is used for
|
||||
* both receiving and sending.
|
||||
*
|
||||
* For datagram (SK_UDP, SK_IP) sockets, there are two ways to handle
|
||||
* source address. The socket could be bound to it using bind()
|
||||
* syscall, but that also forbids the reception of multicast packets,
|
||||
* or the address could be set on per-packet basis using platform
|
||||
* dependent options (but these are not available in some corner
|
||||
* cases). The first way is used when SKF_BIND is specified, the
|
||||
* second way is used otherwise.
|
||||
* For multicast on SK_UDP or SK_IP sockets set IF and TTL, call
|
||||
* sk_setup_multicast() to enable multicast on that socket, and then use
|
||||
* sk_join_group() and sk_leave_group() to manage a set of received multicast
|
||||
* groups.
|
||||
*
|
||||
* For datagram (SK_UDP, SK_IP) sockets, there are two ways to handle source
|
||||
* address. The socket could be bound to it using bind() syscall, but that also
|
||||
* forbids the reception of multicast packets, or the address could be set on
|
||||
* per-packet basis using platform dependent options (but these are not
|
||||
* available in some corner cases). The first way is used when SKF_BIND is
|
||||
* specified, the second way is used otherwise.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
|
|
@ -981,10 +981,10 @@ bfd_start(struct proto *P)
|
|||
add_tail(&bfd_proto_list, &p->bfd_node);
|
||||
|
||||
birdloop_enter(p->loop);
|
||||
p->rx4_1 = bfd_open_rx_sk(p, 0, 4);
|
||||
p->rx4_m = bfd_open_rx_sk(p, 1, 4);
|
||||
p->rx6_1 = bfd_open_rx_sk(p, 0, 6);
|
||||
p->rx6_m = bfd_open_rx_sk(p, 1, 6);
|
||||
p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
|
||||
p->rx4_m = bfd_open_rx_sk(p, 1, SK_IPV4);
|
||||
p->rx6_1 = bfd_open_rx_sk(p, 0, SK_IPV6);
|
||||
p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
|
||||
birdloop_leave(p->loop);
|
||||
|
||||
bfd_take_requests(p);
|
||||
|
|
|
@ -186,10 +186,11 @@ bfd_err_hook(sock *sk, int err)
|
|||
}
|
||||
|
||||
sock *
|
||||
bfd_open_rx_sk(struct bfd_proto *p, int multihop, int inet_version)
|
||||
bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af)
|
||||
{
|
||||
sock *sk = sk_new(p->tpool);
|
||||
sk->type = SK_UDP;
|
||||
sk->subtype = af;
|
||||
sk->sport = !multihop ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT;
|
||||
sk->data = p;
|
||||
|
||||
|
@ -202,19 +203,6 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int inet_version)
|
|||
sk->priority = sk_priority_control;
|
||||
sk->flags = SKF_THREAD | SKF_LADDR_RX | (!multihop ? SKF_TTL_RX : 0);
|
||||
|
||||
switch (inet_version) {
|
||||
case 4:
|
||||
sk->fam = SK_FAM_IPV4;
|
||||
sk->flags |= SKF_V4ONLY;
|
||||
break;
|
||||
case 6:
|
||||
sk->fam = SK_FAM_IPV6;
|
||||
sk->flags |= SKF_V6ONLY;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
if (sk_open(sk) < 0)
|
||||
goto err;
|
||||
|
||||
|
@ -246,14 +234,6 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
|
|||
sk->ttl = ifa ? 255 : -1;
|
||||
sk->flags = SKF_THREAD | SKF_BIND | SKF_HIGH_PORT;
|
||||
|
||||
if (ipa_is_ip4(local)) {
|
||||
sk->fam = SK_FAM_IPV4;
|
||||
sk->flags |= SKF_V4ONLY;
|
||||
} else {
|
||||
sk->fam = SK_FAM_IPV6;
|
||||
sk->flags |= SKF_V6ONLY;
|
||||
}
|
||||
|
||||
if (sk_open(sk) < 0)
|
||||
goto err;
|
||||
|
||||
|
|
|
@ -108,10 +108,10 @@ ospf_sk_open(struct ospf_iface *ifa)
|
|||
|
||||
sock *sk = sk_new(ifa->pool);
|
||||
sk->type = SK_IP;
|
||||
sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
|
||||
sk->dport = OSPF_PROTO;
|
||||
sk->saddr = ifa->addr->ip;
|
||||
sk->iface = ifa->iface;
|
||||
sk->fam = ospf_is_v2(p) ? SK_FAM_IPV4 : SK_FAM_IPV6;
|
||||
|
||||
sk->tos = ifa->cf->tx_tos;
|
||||
sk->priority = ifa->cf->tx_priority;
|
||||
|
@ -193,8 +193,8 @@ ospf_open_vlink_sk(struct ospf_proto *p)
|
|||
{
|
||||
sock *sk = sk_new(p->p.pool);
|
||||
sk->type = SK_IP;
|
||||
sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
|
||||
sk->dport = OSPF_PROTO;
|
||||
sk->fam = ospf_is_v2(p) ? SK_FAM_IPV4 : SK_FAM_IPV6;
|
||||
|
||||
/* FIXME: configurable tos/priority ? */
|
||||
sk->tos = IP_PREC_INTERNET_CONTROL;
|
||||
|
|
|
@ -410,9 +410,9 @@ radv_sk_open(struct radv_iface *ifa)
|
|||
{
|
||||
sock *sk = sk_new(ifa->ra->p.pool);
|
||||
sk->type = SK_IP;
|
||||
sk->subtype = SK_IPV6;
|
||||
sk->dport = ICMPV6_PROTO;
|
||||
sk->saddr = ifa->addr->ip;
|
||||
sk->fam = SK_FAM_IPV6;
|
||||
|
||||
sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */
|
||||
sk->rx_hook = radv_rx_hook;
|
||||
|
|
|
@ -123,7 +123,7 @@ rip_iface_item:
|
|||
| MODE MULTICAST { RIP_IFACE->mode = RIP_IM_MULTICAST; }
|
||||
| MODE BROADCAST { RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng()) cf_error("Broadcast not supported in RIPng"); }
|
||||
| PASSIVE bool { RIP_IFACE->passive = $2; }
|
||||
| ADDRESS ipa { RIP_IFACE->address = $2; }
|
||||
| ADDRESS ipa { RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2()) cf_error("IP address version mismatch"); }
|
||||
| PORT expr { RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
|
||||
| VERSION expr { RIP_IFACE->version = $2;
|
||||
if (rip_cfg_is_ng()) cf_error("Version not supported in RIPng");
|
||||
|
|
|
@ -715,7 +715,7 @@ rip_open_socket(struct rip_iface *ifa)
|
|||
|
||||
sock *sk = sk_new(p->p.pool);
|
||||
sk->type = SK_UDP;
|
||||
sk->fam = rip_is_v2(p) ? SK_FAM_IPV4 : SK_FAM_IPV6;
|
||||
sk->subtype = rip_is_v2(p) ? SK_IPV4 : SK_IPV6;
|
||||
sk->sport = ifa->cf->port;
|
||||
sk->dport = ifa->cf->port;
|
||||
sk->iface = ifa->iface;
|
||||
|
@ -736,8 +736,7 @@ rip_open_socket(struct rip_iface *ifa)
|
|||
sk->tos = ifa->cf->tx_tos;
|
||||
sk->priority = ifa->cf->tx_priority;
|
||||
sk->ttl = ifa->cf->ttl_security ? 255 : 1;
|
||||
sk->flags = SKF_LADDR_RX | (rip_is_ng(p) ? SKF_V6ONLY : 0) |
|
||||
((ifa->cf->ttl_security == 1) ? SKF_TTL_RX : 0);
|
||||
sk->flags = SKF_LADDR_RX | ((ifa->cf->ttl_security == 1) ? SKF_TTL_RX : 0);
|
||||
|
||||
/* sk->rbsize and sk->tbsize are handled in rip_iface_update_buffers() */
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa
|
|||
struct tcp_md5sig md5;
|
||||
|
||||
memset(&md5, 0, sizeof(md5));
|
||||
sockaddr_fill((sockaddr *) &md5.tcpm_addr, fam_to_af[s->fam], remote, ifa, 0);
|
||||
sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0);
|
||||
|
||||
if (passwd)
|
||||
{
|
||||
|
|
|
@ -587,7 +587,6 @@ sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port)
|
|||
return -1;
|
||||
}
|
||||
|
||||
const int fam_to_af[] = { [SK_FAM_IPV4] = AF_INET, [SK_FAM_IPV6] = AF_INET6 };
|
||||
|
||||
/*
|
||||
* IPv6 multicast syscalls
|
||||
|
@ -1194,7 +1193,7 @@ sk_setup(sock *s)
|
|||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
ERR("O_NONBLOCK");
|
||||
|
||||
if (!s->fam)
|
||||
if (!s->af)
|
||||
return 0;
|
||||
|
||||
if (ipa_nonzero(s->saddr) && !(s->flags & SKF_BIND))
|
||||
|
@ -1254,7 +1253,6 @@ sk_setup(sock *s)
|
|||
|
||||
if (sk_is_ipv6(s))
|
||||
{
|
||||
if (s->flags & SKF_V6ONLY)
|
||||
if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &y, sizeof(y)) < 0)
|
||||
ERR("IPV6_V6ONLY");
|
||||
|
||||
|
@ -1295,7 +1293,7 @@ sk_tcp_connected(sock *s)
|
|||
int sa_len = sizeof(sa);
|
||||
|
||||
if ((getsockname(s->fd, &sa.sa, &sa_len) < 0) ||
|
||||
(sockaddr_read(&sa, fam_to_af[s->fam], &s->saddr, &s->iface, &s->sport) < 0))
|
||||
(sockaddr_read(&sa, s->af, &s->saddr, &s->iface, &s->sport) < 0))
|
||||
log(L_WARN "SOCK: Cannot get local IP address for TCP>");
|
||||
|
||||
s->type = SK_TCP;
|
||||
|
@ -1320,7 +1318,7 @@ sk_passive_connected(sock *s, int type)
|
|||
|
||||
sock *t = sk_new(s->pool);
|
||||
t->type = type;
|
||||
t->fam = s->fam;
|
||||
t->af = s->af;
|
||||
t->fd = fd;
|
||||
t->ttl = s->ttl;
|
||||
t->tos = s->tos;
|
||||
|
@ -1330,10 +1328,10 @@ sk_passive_connected(sock *s, int type)
|
|||
if (type == SK_TCP)
|
||||
{
|
||||
if ((getsockname(fd, &loc_sa.sa, &loc_sa_len) < 0) ||
|
||||
(sockaddr_read(&loc_sa, fam_to_af[s->fam], &t->saddr, &t->iface, &t->sport) < 0))
|
||||
(sockaddr_read(&loc_sa, s->af, &t->saddr, &t->iface, &t->sport) < 0))
|
||||
log(L_WARN "SOCK: Cannot get local IP address for TCP<");
|
||||
|
||||
if (sockaddr_read(&rem_sa, fam_to_af[s->fam], &t->daddr, &t->iface, &t->dport) < 0)
|
||||
if (sockaddr_read(&rem_sa, s->af, &t->daddr, &t->iface, &t->dport) < 0)
|
||||
log(L_WARN "SOCK: Cannot get remote IP address for TCP<");
|
||||
}
|
||||
|
||||
|
@ -1368,40 +1366,74 @@ sk_passive_connected(sock *s, int type)
|
|||
int
|
||||
sk_open(sock *s)
|
||||
{
|
||||
int af = AF_UNSPEC;
|
||||
int fd = -1;
|
||||
int do_bind = 0;
|
||||
int bind_port = 0;
|
||||
ip_addr bind_addr = IPA_NONE;
|
||||
sockaddr sa;
|
||||
|
||||
if (s->type <= SK_IP)
|
||||
{
|
||||
/*
|
||||
* For TCP/IP sockets, Address family (IPv4 or IPv6) can be specified either
|
||||
* explicitly (SK_IPV4 or SK_IPV6) or implicitly (based on saddr, daddr).
|
||||
* But the specifications have to be consistent.
|
||||
*/
|
||||
|
||||
switch (s->subtype)
|
||||
{
|
||||
case 0:
|
||||
ASSERT(ipa_zero(s->saddr) || ipa_zero(s->daddr) ||
|
||||
(ipa_is_ip4(s->saddr) == ipa_is_ip4(s->daddr)));
|
||||
af = (ipa_is_ip4(s->saddr) || ipa_is_ip4(s->daddr)) ? AF_INET : AF_INET6;
|
||||
break;
|
||||
|
||||
case SK_IPV4:
|
||||
ASSERT(ipa_zero(s->saddr) || ipa_is_ip4(s->saddr));
|
||||
ASSERT(ipa_zero(s->daddr) || ipa_is_ip4(s->daddr));
|
||||
af = AF_INET;
|
||||
break;
|
||||
|
||||
case SK_IPV6:
|
||||
ASSERT(ipa_zero(s->saddr) || !ipa_is_ip4(s->saddr));
|
||||
ASSERT(ipa_zero(s->daddr) || !ipa_is_ip4(s->daddr));
|
||||
af = AF_INET6;
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("Invalid subtype %d", s->subtype);
|
||||
}
|
||||
}
|
||||
|
||||
switch (s->type)
|
||||
{
|
||||
case SK_TCP_ACTIVE:
|
||||
s->ttx = ""; /* Force s->ttx != s->tpos */
|
||||
/* Fall thru */
|
||||
case SK_TCP_PASSIVE:
|
||||
fd = socket(fam_to_af[s->fam], SOCK_STREAM, IPPROTO_TCP);
|
||||
fd = socket(af, SOCK_STREAM, IPPROTO_TCP);
|
||||
bind_port = s->sport;
|
||||
bind_addr = s->saddr;
|
||||
do_bind = bind_port || ipa_nonzero(bind_addr);
|
||||
break;
|
||||
|
||||
case SK_UDP:
|
||||
fd = socket(fam_to_af[s->fam], SOCK_DGRAM, IPPROTO_UDP);
|
||||
fd = socket(af, SOCK_DGRAM, IPPROTO_UDP);
|
||||
bind_port = s->sport;
|
||||
bind_addr = (s->flags & SKF_BIND) ? s->saddr : IPA_NONE;
|
||||
do_bind = 1;
|
||||
break;
|
||||
|
||||
case SK_IP:
|
||||
fd = socket(fam_to_af[s->fam], SOCK_RAW, s->dport);
|
||||
fd = socket(af, SOCK_RAW, s->dport);
|
||||
bind_port = 0;
|
||||
bind_addr = (s->flags & SKF_BIND) ? s->saddr : IPA_NONE;
|
||||
do_bind = ipa_nonzero(bind_addr);
|
||||
break;
|
||||
|
||||
case SK_MAGIC:
|
||||
s->fam = SK_FAM_NONE;
|
||||
af = 0;
|
||||
fd = s->fd;
|
||||
break;
|
||||
|
||||
|
@ -1412,6 +1444,7 @@ sk_open(sock *s)
|
|||
if (fd < 0)
|
||||
ERR("socket");
|
||||
|
||||
s->af = af;
|
||||
s->fd = fd;
|
||||
|
||||
if (sk_setup(s) < 0)
|
||||
|
@ -1440,7 +1473,7 @@ sk_open(sock *s)
|
|||
if (sk_set_high_port(s) < 0)
|
||||
log(L_WARN "Socket error: %s%#m", s->err);
|
||||
|
||||
sockaddr_fill(&sa, fam_to_af[s->fam], bind_addr, s->iface, bind_port);
|
||||
sockaddr_fill(&sa, s->af, bind_addr, s->iface, bind_port);
|
||||
if (bind(fd, &sa.sa, SA_LEN(sa)) < 0)
|
||||
ERR2("bind");
|
||||
}
|
||||
|
@ -1452,7 +1485,7 @@ sk_open(sock *s)
|
|||
switch (s->type)
|
||||
{
|
||||
case SK_TCP_ACTIVE:
|
||||
sockaddr_fill(&sa, fam_to_af[s->fam], s->daddr, s->iface, s->dport);
|
||||
sockaddr_fill(&sa, s->af, s->daddr, s->iface, s->dport);
|
||||
if (connect(fd, &sa.sa, SA_LEN(sa)) >= 0)
|
||||
sk_tcp_connected(s);
|
||||
else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS &&
|
||||
|
@ -1559,7 +1592,7 @@ sk_sendmsg(sock *s)
|
|||
byte cmsg_buf[CMSG_TX_SPACE];
|
||||
sockaddr dst;
|
||||
|
||||
sockaddr_fill(&dst, fam_to_af[s->fam], s->daddr, s->iface, s->dport);
|
||||
sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_name = &dst.sa,
|
||||
|
@ -1612,7 +1645,7 @@ sk_recvmsg(sock *s)
|
|||
// rv = ipv4_skip_header(pbuf, rv);
|
||||
//endif
|
||||
|
||||
sockaddr_read(&src, fam_to_af[s->fam], &s->faddr, NULL, &s->fport);
|
||||
sockaddr_read(&src, s->af, &s->faddr, NULL, &s->fport);
|
||||
sk_process_cmsgs(s, &msg);
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC)
|
||||
|
@ -1832,7 +1865,7 @@ sk_write(sock *s)
|
|||
case SK_TCP_ACTIVE:
|
||||
{
|
||||
sockaddr sa;
|
||||
sockaddr_fill(&sa, fam_to_af[s->fam], s->daddr, s->iface, s->dport);
|
||||
sockaddr_fill(&sa, s->af, s->daddr, s->iface, s->dport);
|
||||
|
||||
if (connect(s->fd, &sa.sa, SA_LEN(sa)) >= 0 || errno == EISCONN)
|
||||
sk_tcp_connected(s);
|
||||
|
@ -1853,10 +1886,10 @@ sk_write(sock *s)
|
|||
}
|
||||
|
||||
int sk_is_ipv4(sock *s)
|
||||
{ return s->fam == SK_FAM_IPV4; }
|
||||
{ return s->af == AF_INET; }
|
||||
|
||||
int sk_is_ipv6(sock *s)
|
||||
{ return s->fam == SK_FAM_IPV6; }
|
||||
{ return s->af == AF_INET6; }
|
||||
|
||||
void
|
||||
sk_dump_all(void)
|
||||
|
|
|
@ -102,8 +102,6 @@ int sk_open_unix(struct birdsock *s, char *name);
|
|||
void *tracked_fopen(struct pool *, char *name, char *mode);
|
||||
void test_old_bird(char *path);
|
||||
|
||||
extern const int fam_to_af[];
|
||||
|
||||
/* krt.c bits */
|
||||
|
||||
void krt_io_init(void);
|
||||
|
|
Loading…
Reference in a new issue