From 08b3a24da5bbd1bab09d6a2400cdf7705d5e18a7 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 17 May 2016 15:21:49 +0200 Subject: [PATCH] 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. --- lib/socket.h | 46 +++++++++++++++------------- proto/bfd/bfd.c | 8 ++--- proto/bfd/packets.c | 24 ++------------- proto/ospf/iface.c | 4 +-- proto/radv/packets.c | 2 +- proto/rip/config.Y | 2 +- proto/rip/packets.c | 5 ++- sysdep/linux/sysio.h | 2 +- sysdep/unix/io.c | 73 ++++++++++++++++++++++++++++++++------------ sysdep/unix/unix.h | 2 -- 10 files changed, 91 insertions(+), 77 deletions(-) diff --git a/lib/socket.h b/lib/socket.h index d12ea3c5..7d1aa7ef 100644 --- a/lib/socket.h +++ b/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 diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index f966161c..d33424b0 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -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); diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index b7a057f1..579064c6 100644 --- a/proto/bfd/packets.c +++ b/proto/bfd/packets.c @@ -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; diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 4548f6da..6ef24ffe 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -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; diff --git a/proto/radv/packets.c b/proto/radv/packets.c index 8f6a1913..915b412f 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -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; diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 3c8cd0f2..61a2a101 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -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"); diff --git a/proto/rip/packets.c b/proto/rip/packets.c index 488ac9df..f89bb178 100644 --- a/proto/rip/packets.c +++ b/proto/rip/packets.c @@ -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() */ diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 3c07a3e7..58644417 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -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) { diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 69c17d60..48f368a4 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -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,9 +1253,8 @@ 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"); + if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &y, sizeof(y)) < 0) + ERR("IPV6_V6ONLY"); if (s->flags & SKF_LADDR_RX) if (sk_request_cmsg6_pktinfo(s) < 0) @@ -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) diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 80c99350..dcaab729 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -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);