From d28210b2c2aaf3200907ed30d296b0d4856dd03c Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Sat, 16 Jan 2021 23:06:32 +0000 Subject: [PATCH] Remove remnants of classful behavior in route(8). Curently route(8) treats some addresses as network addresses: RTA_DST: inet 10.0.0.0; RTA_NETMASK: inet 255.0.0.0; RTA_IFP: link ; RTM_GET: Report Metrics: len 240, pid: 0, seq 1, errno 0, flags: locks: inits: sockaddrs: 10.0.0.0 255.0.0.0 link#0 Note added `RTA_NETMASK` in the request. Host address from the same network is ok: route -nv get 10.0.0.1 RTA_DST: inet 10.0.0.1 RTA_IFP: link RTM_GET: Report Metrics: len 224, pid: 0, seq 1, errno 0, flags: ... route to: 10.0.0.1 destination: 10.0.0.0 mask: 255.255.255.0 This change eliminates network auto-guessing part AND reading network from /etc/networks. Reviewed By: rgrimes Differential Revision: https://reviews.freebsd.org/D24401 --- sbin/route/route.c | 69 ++++++++++------------------------------------ 1 file changed, 14 insertions(+), 55 deletions(-) diff --git a/sbin/route/route.c b/sbin/route/route.c index 9c9e4b304848..51a0c68746a6 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -120,8 +120,7 @@ static int flushroutes_fib(int); static int getaddr(int, char *, struct hostent **, int); static int keyword(const char *); #ifdef INET -static void inet_makenetandmask(u_long, struct sockaddr_in *, - struct sockaddr_in *, u_long); +static void inet_makemask(struct sockaddr_in *, u_long); #endif #ifdef INET6 static int inet6_makenetandmask(struct sockaddr_in6 *, const char *); @@ -1113,40 +1112,15 @@ newroute_fib(int fib, char *cmd, int flags) #ifdef INET static void -inet_makenetandmask(u_long net, struct sockaddr_in *sin, - struct sockaddr_in *sin_mask, u_long bits) +inet_makemask(struct sockaddr_in *sin_mask, u_long bits) { u_long mask = 0; rtm_addrs |= RTA_NETMASK; - /* - * MSB of net should be meaningful. 0/0 is exception. - */ - if (net > 0) - while ((net & 0xff000000) == 0) - net <<= 8; - - /* - * If no /xx was specified we must calculate the - * CIDR address. - */ - if ((bits == 0) && (net != 0)) { - u_long i, j; - - for(i = 0, j = 0xff; i < 4; i++) { - if (net & j) { - break; - } - j <<= 8; - } - /* i holds the first non zero bit */ - bits = 32 - (i*8); - } if (bits != 0) mask = 0xffffffff << (32 - bits); - sin->sin_addr.s_addr = htonl(net); sin_mask->sin_addr.s_addr = htonl(mask); sin_mask->sin_len = sizeof(struct sockaddr_in); sin_mask->sin_family = AF_INET; @@ -1186,8 +1160,6 @@ getaddr(int idx, char *str, struct hostent **hpp, int nrflags) #if defined(INET) struct sockaddr_in *sin; struct hostent *hp; - struct netent *np; - u_long val; char *q; #elif defined(INET6) char *q; @@ -1314,34 +1286,21 @@ getaddr(int idx, char *str, struct hostent **hpp, int nrflags) q = strchr(str,'/'); if (q != NULL && idx == RTAX_DST) { + /* A.B.C.D/NUM */ *q = '\0'; - if ((val = inet_network(str)) != INADDR_NONE) { - inet_makenetandmask(val, sin, - (struct sockaddr_in *)&so[RTAX_NETMASK], - strtoul(q+1, 0, 0)); - return (0); - } - *q = '/'; - } - if ((idx != RTAX_DST || (nrflags & F_FORCENET) == 0) && - inet_aton(str, &sin->sin_addr)) { - val = sin->sin_addr.s_addr; - if (idx != RTAX_DST || nrflags & F_FORCEHOST || - inet_lnaof(sin->sin_addr) != INADDR_ANY) - return (1); - else { - val = ntohl(val); - goto netdone; - } - } - if (idx == RTAX_DST && (nrflags & F_FORCEHOST) == 0 && - ((val = inet_network(str)) != INADDR_NONE || - ((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) { -netdone: - inet_makenetandmask(val, sin, - (struct sockaddr_in *)&so[RTAX_NETMASK], 0); + if (inet_aton(str, &sin->sin_addr) == 0) + errx(EX_NOHOST, "bad address: %s", str); + + int masklen = strtol(q + 1, NULL, 10); + if (masklen < 0 || masklen > 32) + errx(EX_NOHOST, "bad mask length: %s", q + 1); + + inet_makemask((struct sockaddr_in *)&so[RTAX_NETMASK],masklen); return (0); } + if (inet_aton(str, &sin->sin_addr) != 0) + return (1); + hp = gethostbyname(str); if (hp != NULL) { *hpp = hp;