On Fri, Mar 22, 2019 at 09:57:29PM +0100, Michał Koc wrote: > W dniu 22.03.2019 o 11:19, Michał Koc pisze: > > W dniu 21.03.2019 o 11:52, Otto Moerbeek pisze: > > > On Thu, Mar 21, 2019 at 09:28:28AM +0100, Michał Koc wrote: > > > > > > > W dniu 21.03.2019 o 07:21, Otto Moerbeek pisze: > > > > > On Thu, Mar 21, 2019 at 12:51:11AM +0100, Klemens Nanni wrote: > > > > > > On Tue, Mar 12, 2019 at 03:19:56PM +0100, Otto Moerbeek wrote: > > > > > > > > I also fixed a case of parsing IPv6 addresses. > > > > > > > > > > > > > > > > Anyone willing to ok? > > > > > > See comments inline. > > > > > > > > > > > > > And now also with a lexer bug fixed. Earlier I > > > > > > > thougt it was an order > > > > > > > dependency in the clauses. But is was an order dependency in > > > > > > > comment > > > > > > > lines and empty lines. > > > > > > > +check_peer_addr(const char *peer_addr) > > > > > > > +{ > > > > > > > + int valid = 1; > > > > > > > + short peer_family = AF_UNSPEC; > > > > > > > + struct ifaddrs *ifap = NULL, *ifa; > > > > > > > + struct syncpeer *peer; > > > > > > > + struct sockaddr_in sa; > > > > > > > + struct sockaddr_in6 sa6; > > > > > > > + > > > > > > > + if (inet_pton(AF_INET, peer_addr, &sa.sin_addr) == 1) > > > > > > > + peer_family = AF_INET; > > > > > > > + > > > > > > > + if (peer_family == AF_UNSPEC && inet_pton(AF_INET6, > > > > > > > peer_addr, > > > > > > > + &sa6.sin6_addr) == 1) > > > > > > > + peer_family = AF_INET6; > > > > > > `peer_addr' must not be a CIDR network, so I'd go with the more AF > > > > > > agnostic getaddrinfo(3) and check for res->ai_family in any case... > > > > > > > > > > > > > + if (peer_family == AF_UNSPEC) { > > > > > > > + log_msg(2, "config: skip unparseable peer %s", > > > > > > > peer_addr); > > > > > > > + valid = 0; > > > > > > > + } > > > > > > ..but `peer_addr' may also be a hostname, so that is not handled by > > > > > > your diff: > > > > > > > > > > > > net.h: char *name; /* FQDN or an IP, from conf > > > > > > */ > > > > > > > > > > > > getaddrinfo(3) can resolve however, thus inet_pton(3) > > > > > > should not be used > > > > > > here. > > > > > > > > > > > > Either way, this is a job for host_ip() as found in pfctl or bgpd. > > > > > > Other daemons like iked still have host_v4() and > > > > > > host_v6(). Parsers use > > > > > > these functions to check for valid addresses, so I'd say > > > > > > sasyncd should > > > > > > be no exception and adopt the same approach. > > > > > > > > > > > > > @@ -325,7 +386,7 @@ yylex(void) > > > > > > > /* Numerical token? */ > > > > > > > if (isdigit(*confptr)) { > > > > > > > for (p = confptr; *p; p++) > > > > > > > - if (*p == '.') /* IP address, or bad input */ > > > > > > > + if (*p == '.' || *p == ':') /* IP > > > > > > > address, or bad input */ > > > > > > This fixes the parser as in > > > > > > > > > > > > # echo peer 2001:db8::1 > conf > > > > > > # sasyncd -dnv -c conf > > > > > > config: syntax error > > > > > > # ./obj/sasyncd -dnv -c conf > > > > > > configuration OK > > > > > > > > > > > > But I have not actually tested this with a proper IPv6 > > > > > > setup since I do > > > > > > not use sasyncd; did you? > > > > > > > > > > > > > @@ -397,6 +458,9 @@ conf_parse_file(char *cfgfile) > > > > > > > if (*s == '#') { > > > > > > > while (*s != '\n' && s < buf + conflen) > > > > > > > s++; > > > > > > > + while (*s == '\n' && s < buf + conflen) > > > > > > > + s++; > > > > > > > + s--; > > > > > > OK kn for this fix alone. > > > > > > > > > > > I'll test an ipv6 seup and commit the lexer parts if those work. > > > > > Michal, can you work on the first set of comments? I think Klemens is > > > > > right. > > > > > > > > > > -Otto > > > > > > > > > Of course, I'll follow the comments soon > > > > > > > > Best Regards > > > > M.K. > > > > the diff is ready, what happened here: > > > > 1. host => ip manipulation moved to host_ip() function in net.c and is > > using getaddrinfo() > > 2. net_set_sa() in net.c modified to use host_ip() > > > > Bets Regards > > M.K > > Do not actually compare two structs sockaddr if their lengths differ. >
I did not have time yet to run this code, but some comments inline. -Otto > Index: conf.y > =================================================================== > RCS file: /cvs/src/usr.sbin/sasyncd/conf.y,v > retrieving revision 1.19 > diff -u -p -r1.19 conf.y > --- conf.y 9 Apr 2017 02:40:24 -0000 1.19 > +++ conf.y 22 Mar 2019 20:55:21 -0000 > @@ -30,8 +30,10 @@ > #include <sys/types.h> > #include <sys/stat.h> > #include <sys/socket.h> > +#include <arpa/inet.h> > #include <ctype.h> > #include <fcntl.h> > +#include <ifaddrs.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > @@ -48,6 +50,7 @@ struct cfgstate cfgstate; > int conflen = 0; > char *confbuf, *confptr; > > +int check_peer_addr(const char *); > int yyparse(void); > int yylex(void); > void yyerror(const char *); > @@ -172,17 +175,8 @@ setting : INTERFACE STRING > | PEER STRING > { > struct syncpeer *peer; > - int duplicate = 0; > > - for (peer = LIST_FIRST(&cfgstate.peerlist); peer; > - peer = LIST_NEXT(peer, link)) > - if (strcmp($2, peer->name) == 0) { > - duplicate++; > - break; > - } > - if (duplicate) > - free($2); > - else { > + if (check_peer_addr($2)) { > peer = calloc(1, sizeof *peer); > if (!peer) { > log_err("config: calloc(1, %lu) " > @@ -191,10 +185,11 @@ setting : INTERFACE STRING > YYERROR; > } > peer->name = $2; > - } > - LIST_INSERT_HEAD(&cfgstate.peerlist, peer, link); > - cfgstate.peercnt++; > - log_msg(2, "config: add peer %s", peer->name); > + LIST_INSERT_HEAD(&cfgstate.peerlist, peer, > link); > + cfgstate.peercnt++; > + log_msg(2, "config: add peer %s", peer->name); > + } else > + free($2); > } > | LISTEN ON STRING af port > { > @@ -281,6 +276,51 @@ match(char *token) > sizeof keywords[0], match_cmp); > > return k ? k->value : STRING; > +} > + > +int > +check_peer_addr(const char *peer_addr) > +{ > + struct ifaddrs *ifap = 0, *ifa; > + struct syncpeer *peer; > + struct sockaddr *sa, *peer_sa; > + > + sa = host_ip(peer_addr); > + > + if(!sa) I prefer comparing to NULL for pointers. > + log_msg(2, "config: skip unparseable peer %s", peer_addr); > + > + if (sa && getifaddrs(&ifap) == 0) { > + for (ifa = ifap; ifa && sa; ifa = ifa->ifa_next) { > + if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != > sa->sa_family) Same here. > + continue; > + > + if (sa->sa_len == ifa->ifa_addr->sa_len && memcmp(sa, > ifa->ifa_addr, sa->sa_len) == 0) { > + log_msg(2, "config: skip local peer %s", > peer_addr); > + free(sa); > + sa = 0; Use NULL for pointers. > + } > + } > + freeifaddrs(ifap); > + } > + > + if (sa) { > + for (peer = LIST_FIRST(&cfgstate.peerlist); peer && sa; > + peer = LIST_NEXT(peer, link)) { > + peer_sa = host_ip(peer->name); > + > + if (sa->sa_len == peer_sa->sa_len && memcmp(sa, peer_sa, > sa->sa_len) == 0) { > + log_msg(2, "config: skip duplicate peer %s", peer_addr); > + free(sa); > + sa = 0; Use NULL. > + } > + free(peer_sa); > + } > + } > + > + free(sa); > + > + return sa != 0; And here > } > > int > Index: net.c > =================================================================== > RCS file: /cvs/src/usr.sbin/sasyncd/net.c,v > retrieving revision 1.23 > diff -u -p -r1.23 net.c > --- net.c 12 Dec 2015 20:04:23 -0000 1.23 > +++ net.c 22 Mar 2019 20:55:21 -0000 > @@ -755,32 +755,26 @@ net_read(struct syncpeer *p, u_int32_t * > static int > net_set_sa(struct sockaddr *sa, char *name, in_port_t port) > { > - struct sockaddr_in *sin = (struct sockaddr_in *)sa; > - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; > + struct sockaddr *peer_sa = host_ip(name); > > - if (!name) { > - /* XXX Assume IPv4 */ > - sa->sa_family = AF_INET; > - sin->sin_port = htons(port); > - sin->sin_len = sizeof *sin; > - return 0; > - } > + if (peer_sa) { > > - if (inet_pton(AF_INET, name, &sin->sin_addr) == 1) { > - sa->sa_family = AF_INET; > - sin->sin_port = htons(port); > - sin->sin_len = sizeof *sin; > - return 0; > - } > + memcpy(sa, peer_sa, peer_sa->sa_len); > + free(peer_sa); > + > + switch(sa->sa_family) { > + case AF_INET: > + ((struct sockaddr_in *)sa)->sin_port = htons(port); > + break; > + > + case AF_INET6: > + ((struct sockaddr_in6 *)sa)->sin6_port = htons(port); > + break; > + } > > - if (inet_pton(AF_INET6, name, &sin6->sin6_addr) == 1) { > - sa->sa_family = AF_INET6; > - sin6->sin6_port = htons(port); > - sin6->sin6_len = sizeof *sin6; > - return 0; > } > > - return -1; > + return peer_sa == 0 ? -1 : 0; Use NULL > } > > static void > @@ -848,4 +842,24 @@ net_check_peers(void *arg) > { > net_connect(); > (void)timer_add("peer recheck", 600, net_check_peers, 0); > +} > + > +struct sockaddr * > +host_ip(const char *hostname) { > + struct addrinfo *ai = 0; > + struct sockaddr *sa = 0; > + > + if (getaddrinfo(hostname, NULL, NULL, &ai) == 0) { > + > + switch (ai->ai_family) { > + case AF_INET: > + case AF_INET6: > + sa = calloc(1, ai->ai_addr->sa_len); > + memcpy(sa, ai->ai_addr, ai->ai_addr->sa_len); Always check return value of allocations! Why use calloc if you are going to overwrite thw whole chunk? > + break; > + } > + freeaddrinfo(ai); > + } > + > + return sa; > } > Index: net.h > =================================================================== > RCS file: /cvs/src/usr.sbin/sasyncd/net.h,v > retrieving revision 1.5 > diff -u -p -r1.5 net.h > --- net.h 2 Jun 2006 20:09:43 -0000 1.5 > +++ net.h 22 Mar 2019 20:55:21 -0000 > @@ -53,6 +53,7 @@ enum CTLTYPE { RESERVED = 0, CTL_STATE, > /* net.c */ > void net_connect(void); > void net_disconnect_peer(struct syncpeer *); > +struct sockaddr *host_ip(const char *); > > /* net_ctl.c */ > void net_ctl_handle_msg(struct syncpeer *, u_int8_t *, u_int32_t);