rtquery.c revision 32502
118316Swollman/*- 218316Swollman * Copyright (c) 1982, 1986, 1993 318316Swollman * The Regents of the University of California. All rights reserved. 418316Swollman * 518316Swollman * Redistribution and use in source and binary forms, with or without 618316Swollman * modification, are permitted provided that the following conditions 718316Swollman * are met: 818316Swollman * 1. Redistributions of source code must retain the above copyright 918316Swollman * notice, this list of conditions and the following disclaimer. 1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1118316Swollman * notice, this list of conditions and the following disclaimer in the 1218316Swollman * documentation and/or other materials provided with the distribution. 1318316Swollman * 3. All advertising materials mentioning features or use of this software 1418316Swollman * must display the following acknowledgement: 1518316Swollman * This product includes software developed by the University of 1618316Swollman * California, Berkeley and its contributors. 1718316Swollman * 4. Neither the name of the University nor the names of its contributors 1818316Swollman * may be used to endorse or promote products derived from this software 1918316Swollman * without specific prior written permission. 2018316Swollman * 2118316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2218316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2318316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2418316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2518316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2618316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2718316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2818316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2918316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3018316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3118316Swollman * SUCH DAMAGE. 3218316Swollman */ 3318316Swollman 3432502Scharnier#ifndef lint 3532502Scharnierstatic const char copyright[] = 3618316Swollman"@(#) Copyright (c) 1982, 1986, 1993\n\ 3718316Swollman The Regents of the University of California. All rights reserved.\n"; 3832502Scharnier#endif /* not lint */ 3918316Swollman 4032502Scharnier#ifndef lint 4132502Scharnier#if 0 4218316Swollmanstatic char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93"; 4318316Swollman#endif 4432502Scharnierstatic const char rcsid[] = 4532502Scharnier "$Id$"; 4632502Scharnier#endif /* not lint */ 4718316Swollman 4818316Swollman#include <sys/param.h> 4918316Swollman#include <sys/socket.h> 5018316Swollman#include <sys/time.h> 5118316Swollman#include <netinet/in.h> 5218316Swollman#define RIPVERSION RIPv2 5318316Swollman#include <protocols/routed.h> 5418316Swollman#include <arpa/inet.h> 5532502Scharnier#include <err.h> 5632502Scharnier#include <errno.h> 5718316Swollman#include <netdb.h> 5818316Swollman#include <stdio.h> 5918316Swollman#include <stdlib.h> 6018316Swollman#include <string.h> 6132502Scharnier#include <unistd.h> 6218316Swollman#ifdef sgi 6318316Swollman#include <strings.h> 6418316Swollman#include <bstring.h> 6518316Swollman#endif 6618316Swollman 6718316Swollman#ifndef sgi 6818316Swollman#define _HAVE_SIN_LEN 6918316Swollman#endif 7018316Swollman 7119885Swollman#include <md5.h> 7218316Swollman#define WTIME 15 /* Time to wait for all responses */ 7318316Swollman#define STIME (250*1000) /* usec to wait for another response */ 7418316Swollman 7518316Swollmanint s; 7618316Swollman 7718316Swollmanunion { 7818316Swollman struct rip rip; 7918316Swollman char packet[MAXPACKETSIZE+MAXPATHLEN]; 8018316Swollman} omsg_buf; 8118316Swollman#define OMSG omsg_buf.rip 8218316Swollmanint omsg_len = sizeof(struct rip); 8318316Swollman 8418316Swollmanunion { 8518316Swollman struct rip rip; 8618316Swollman char packet[MAXPACKETSIZE+1024]; 8718316Swollman } imsg_buf; 8818316Swollman#define IMSG imsg_buf.rip 8918316Swollman 9018316Swollmanint nflag; /* numbers, no names */ 9118316Swollmanint pflag; /* play the `gated` game */ 9218316Swollmanint ripv2 = 1; /* use RIP version 2 */ 9318316Swollmanint wtime = WTIME; 9418316Swollmanint rflag; /* 1=ask about a particular route */ 9519880Swollmanint trace, not_trace; /* send trace command or not */ 9619880Swollmanint auth_type = RIP_AUTH_NONE; 9719880Swollmanchar passwd[RIP_AUTH_PW_LEN]; 9819880Swollmanu_long keyid; 9918316Swollman 10018316Swollmanstruct timeval sent; /* when query sent */ 10118316Swollman 10218316Swollmanstatic void rip_input(struct sockaddr_in*, int); 10318316Swollmanstatic int out(char *); 10418316Swollmanstatic void trace_loop(char *argv[]); 10518316Swollmanstatic void query_loop(char *argv[], int); 10618316Swollmanstatic int getnet(char *, struct netinfo *); 10718316Swollmanstatic u_int std_mask(u_int); 10819880Swollmanstatic int parse_quote(char **, char *, char *, char *, int); 10918316Swollman 11018316Swollman 11120609Swollmanvoid 11218316Swollmanmain(int argc, 11318316Swollman char *argv[]) 11418316Swollman{ 11518316Swollman int ch, bsize; 11619880Swollman char *p, *options, *value, delim; 11718316Swollman 11818316Swollman OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 11918316Swollman OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 12018316Swollman OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 12118316Swollman 12224359Simp while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) 12318316Swollman switch (ch) { 12418316Swollman case 'n': 12518316Swollman not_trace = 1; 12618316Swollman nflag = 1; 12718316Swollman break; 12818316Swollman 12918316Swollman case 'p': 13018316Swollman not_trace = 1; 13118316Swollman pflag = 1; 13218316Swollman break; 13318316Swollman 13418316Swollman case '1': 13518316Swollman ripv2 = 0; 13618316Swollman break; 13718316Swollman 13818316Swollman case 'w': 13918316Swollman not_trace = 1; 14018316Swollman wtime = (int)strtoul(optarg, &p, 0); 14118316Swollman if (*p != '\0' 14218316Swollman || wtime <= 0) 14318316Swollman goto usage; 14418316Swollman break; 14518316Swollman 14618316Swollman case 'r': 14718316Swollman not_trace = 1; 14818316Swollman if (rflag) 14918316Swollman goto usage; 15018316Swollman rflag = getnet(optarg, &OMSG.rip_nets[0]); 15118316Swollman if (!rflag) { 15218316Swollman struct hostent *hp = gethostbyname(optarg); 15318316Swollman if (hp == 0) { 15426724Scharnier fprintf(stderr, "rtquery: %s:", optarg); 15518316Swollman herror(0); 15618316Swollman exit(1); 15718316Swollman } 15818316Swollman bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst, 15918316Swollman sizeof(OMSG.rip_nets[0].n_dst)); 16018316Swollman OMSG.rip_nets[0].n_family = RIP_AF_INET; 16118316Swollman OMSG.rip_nets[0].n_mask = -1; 16218316Swollman rflag = 1; 16318316Swollman } 16418316Swollman break; 16518316Swollman 16618316Swollman case 't': 16718316Swollman trace = 1; 16818316Swollman options = optarg; 16918316Swollman while (*options != '\0') { 17018316Swollman char *traceopts[] = { 17118316Swollman# define TRACE_ON 0 17218316Swollman "on", 17318316Swollman# define TRACE_MORE 1 17418316Swollman "more", 17518316Swollman# define TRACE_OFF 2 17618316Swollman "off", 17718316Swollman# define TRACE_DUMP 3 17818316Swollman "dump", 17918316Swollman 0 18018316Swollman }; 18118316Swollman switch (getsubopt(&options,traceopts,&value)) { 18218316Swollman case TRACE_ON: 18318316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 18418316Swollman if (!value 18518316Swollman || strlen(value) > MAXPATHLEN) 18618316Swollman goto usage; 18718316Swollman break; 18818316Swollman case TRACE_MORE: 18918316Swollman if (value) 19018316Swollman goto usage; 19118316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 19218316Swollman value = ""; 19318316Swollman break; 19418316Swollman case TRACE_OFF: 19518316Swollman if (value) 19618316Swollman goto usage; 19718316Swollman OMSG.rip_cmd = RIPCMD_TRACEOFF; 19818316Swollman value = ""; 19918316Swollman break; 20018316Swollman case TRACE_DUMP: 20118316Swollman if (value) 20218316Swollman goto usage; 20318316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 20418316Swollman value = "dump/../table"; 20518316Swollman break; 20618316Swollman default: 20718316Swollman goto usage; 20818316Swollman } 20918316Swollman strcpy((char*)OMSG.rip_tracefile, value); 21018316Swollman omsg_len += strlen(value) - sizeof(OMSG.ripun); 21118316Swollman } 21218316Swollman break; 21318316Swollman 21419880Swollman case 'a': 21519880Swollman not_trace = 1; 21619880Swollman p = strchr(optarg,'='); 21719880Swollman if (!p) 21819880Swollman goto usage; 21919880Swollman *p++ = '\0'; 22019880Swollman if (!strcasecmp("passwd",optarg)) 22119880Swollman auth_type = RIP_AUTH_PW; 22219880Swollman else if (!strcasecmp("md5_passwd",optarg)) 22319880Swollman auth_type = RIP_AUTH_MD5; 22419880Swollman else 22519880Swollman goto usage; 22619880Swollman if (0 > parse_quote(&p,"|",&delim, 22719880Swollman passwd,sizeof(passwd))) 22819880Swollman goto usage; 22919880Swollman if (auth_type == RIP_AUTH_MD5 23019880Swollman && delim == '|') { 23119880Swollman keyid = strtoul(p+1,&p,0); 23219880Swollman if (keyid > 255 || *p != '\0') 23319880Swollman goto usage; 23419880Swollman } else if (delim != '\0') { 23519880Swollman goto usage; 23619880Swollman } 23719880Swollman break; 23819880Swollman 23918316Swollman default: 24018316Swollman goto usage; 24118316Swollman } 24218316Swollman argv += optind; 24318316Swollman argc -= optind; 24418316Swollman if ((not_trace && trace) || argc == 0) { 24526724Scharnierusage: fprintf(stderr, "%s\n%s\n", 24626724Scharnier "usage: rtquery [-np1v] [-r addr] [-w timeout] [-a secret] host ...", 24726724Scharnier " rtquery [-t op] host ..."); 24818316Swollman exit(1); 24918316Swollman } 25018316Swollman 25118316Swollman s = socket(AF_INET, SOCK_DGRAM, 0); 25232502Scharnier if (s < 0) 25332502Scharnier err(2, "socket"); 25418316Swollman 25518316Swollman /* be prepared to receive a lot of routes */ 25618316Swollman for (bsize = 127*1024; ; bsize -= 1024) { 25718316Swollman if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 25818316Swollman &bsize, sizeof(bsize)) == 0) 25918316Swollman break; 26018316Swollman if (bsize <= 4*1024) { 26132502Scharnier warn("setsockopt SO_RCVBUF"); 26218316Swollman break; 26318316Swollman } 26418316Swollman } 26518316Swollman 26618316Swollman if (trace) 26718316Swollman trace_loop(argv); 26818316Swollman else 26918316Swollman query_loop(argv, argc); 27018316Swollman /* NOTREACHED */ 27118316Swollman} 27218316Swollman 27318316Swollman 27418316Swollman/* tell the target hosts about tracing 27518316Swollman */ 27618316Swollmanstatic void 27718316Swollmantrace_loop(char *argv[]) 27818316Swollman{ 27918316Swollman struct sockaddr_in myaddr; 28018316Swollman int res; 28118316Swollman 28232502Scharnier if (geteuid() != 0) 28332502Scharnier errx(1, "-t requires UID 0"); 28418316Swollman 28518316Swollman if (ripv2) { 28618316Swollman OMSG.rip_vers = RIPv2; 28718316Swollman } else { 28818316Swollman OMSG.rip_vers = RIPv1; 28918316Swollman } 29018316Swollman 29118316Swollman bzero(&myaddr, sizeof(myaddr)); 29218316Swollman myaddr.sin_family = AF_INET; 29318316Swollman#ifdef _HAVE_SIN_LEN 29418316Swollman myaddr.sin_len = sizeof(myaddr); 29518316Swollman#endif 29618316Swollman myaddr.sin_port = htons(IPPORT_RESERVED-1); 29718316Swollman while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 29832502Scharnier if (errno != EADDRINUSE || myaddr.sin_port == 0) 29932502Scharnier err(2, "bind"); 30018316Swollman myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 30118316Swollman } 30218316Swollman 30318316Swollman res = 1; 30418316Swollman while (*argv != 0) { 30518316Swollman if (out(*argv++) <= 0) 30618316Swollman res = 0; 30718316Swollman } 30818316Swollman exit(res); 30918316Swollman} 31018316Swollman 31118316Swollman 31218316Swollman/* query all of the listed hosts 31318316Swollman */ 31418316Swollmanstatic void 31518316Swollmanquery_loop(char *argv[], int argc) 31618316Swollman{ 31719880Swollman# define NA0 (OMSG.rip_auths[0]) 31819880Swollman# define NA2 (OMSG.rip_auths[2]) 31918316Swollman struct seen { 32018316Swollman struct seen *next; 32118316Swollman struct in_addr addr; 32218316Swollman } *seen, *sp; 32318316Swollman int answered = 0; 32418316Swollman int cc; 32518316Swollman fd_set bits; 32618316Swollman struct timeval now, delay; 32718316Swollman struct sockaddr_in from; 32818316Swollman int fromlen; 32919880Swollman MD5_CTX md5_ctx; 33018316Swollman 33118316Swollman 33218316Swollman OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 33318316Swollman if (ripv2) { 33418316Swollman OMSG.rip_vers = RIPv2; 33519880Swollman if (auth_type == RIP_AUTH_PW) { 33619880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 33719880Swollman NA0.a_family = RIP_AF_AUTH; 33819880Swollman NA0.a_type = RIP_AUTH_PW; 33919880Swollman bcopy(passwd, NA0.au.au_pw, 34019880Swollman RIP_AUTH_PW_LEN); 34119880Swollman omsg_len += sizeof(OMSG.rip_nets[0]); 34219880Swollman 34319880Swollman } else if (auth_type == RIP_AUTH_MD5) { 34419880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 34519880Swollman NA0.a_family = RIP_AF_AUTH; 34619880Swollman NA0.a_type = RIP_AUTH_MD5; 34719880Swollman NA0.au.a_md5.md5_keyid = (int8_t)keyid; 34819880Swollman NA0.au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN; 34919880Swollman NA0.au.a_md5.md5_seqno = 0; 35019880Swollman NA0.au.a_md5.md5_pkt_len = sizeof(OMSG.rip_nets[1]); 35119880Swollman NA2.a_family = RIP_AF_AUTH; 35219880Swollman NA2.a_type = 1; 35319880Swollman bcopy(passwd, NA2.au.au_pw, sizeof(NA2.au.au_pw)); 35419880Swollman MD5Init(&md5_ctx); 35519880Swollman MD5Update(&md5_ctx, (u_char *)&NA0, 35619880Swollman (char *)(&NA2+1) - (char *)&NA0); 35719880Swollman MD5Final(NA2.au.au_pw, &md5_ctx); 35819880Swollman omsg_len += 2*sizeof(OMSG.rip_nets[0]); 35919880Swollman } 36019880Swollman 36118316Swollman } else { 36218316Swollman OMSG.rip_vers = RIPv1; 36318316Swollman OMSG.rip_nets[0].n_mask = 0; 36418316Swollman } 36518316Swollman 36618316Swollman /* ask the first (valid) host */ 36718316Swollman seen = 0; 36818316Swollman while (0 > out(*argv++)) { 36918316Swollman if (*argv == 0) 37032502Scharnier exit(1); 37118316Swollman answered++; 37218316Swollman } 37318316Swollman 37418316Swollman FD_ZERO(&bits); 37518316Swollman for (;;) { 37618316Swollman FD_SET(s, &bits); 37718316Swollman delay.tv_sec = 0; 37818316Swollman delay.tv_usec = STIME; 37918316Swollman cc = select(s+1, &bits, 0,0, &delay); 38018316Swollman if (cc > 0) { 38118316Swollman fromlen = sizeof(from); 38218316Swollman cc = recvfrom(s, imsg_buf.packet, 38318316Swollman sizeof(imsg_buf.packet), 0, 38418316Swollman (struct sockaddr *)&from, &fromlen); 38532502Scharnier if (cc < 0) 38632502Scharnier err(1, "recvfrom"); 38718316Swollman /* count the distinct responding hosts. 38818316Swollman * You cannot match responding hosts with 38918316Swollman * addresses to which queries were transmitted, 39018316Swollman * because a router might respond with a 39118316Swollman * different source address. 39218316Swollman */ 39318316Swollman for (sp = seen; sp != 0; sp = sp->next) { 39418316Swollman if (sp->addr.s_addr == from.sin_addr.s_addr) 39518316Swollman break; 39618316Swollman } 39718316Swollman if (sp == 0) { 39818316Swollman sp = malloc(sizeof(*sp)); 39918316Swollman sp->addr = from.sin_addr; 40018316Swollman sp->next = seen; 40118316Swollman seen = sp; 40218316Swollman answered++; 40318316Swollman } 40418316Swollman 40518316Swollman rip_input(&from, cc); 40618316Swollman continue; 40718316Swollman } 40818316Swollman 40918316Swollman if (cc < 0) { 41032502Scharnier if (errno == EINTR) 41118316Swollman continue; 41232502Scharnier err(1, "select"); 41318316Swollman } 41418316Swollman 41518316Swollman /* After a pause in responses, probe another host. 41618316Swollman * This reduces the intermingling of answers. 41718316Swollman */ 41818316Swollman while (*argv != 0 && 0 > out(*argv++)) 41918316Swollman answered++; 42018316Swollman 42118316Swollman /* continue until no more packets arrive 42218316Swollman * or we have heard from all hosts 42318316Swollman */ 42418316Swollman if (answered >= argc) 42518316Swollman break; 42618316Swollman 42718316Swollman /* or until we have waited a long time 42818316Swollman */ 42932502Scharnier if (gettimeofday(&now, 0) < 0) 43032502Scharnier err(1, "gettimeofday(now)"); 43118316Swollman if (sent.tv_sec + wtime <= now.tv_sec) 43218316Swollman break; 43318316Swollman } 43418316Swollman 43518316Swollman /* fail if there was no answer */ 43618316Swollman exit (answered >= argc ? 0 : 1); 43718316Swollman} 43818316Swollman 43918316Swollman 44019880Swollman/* send to one host 44118316Swollman */ 44218316Swollmanstatic int 44318316Swollmanout(char *host) 44418316Swollman{ 44518316Swollman struct sockaddr_in router; 44618316Swollman struct hostent *hp; 44718316Swollman 44818316Swollman if (gettimeofday(&sent, 0) < 0) { 44932502Scharnier warn("gettimeofday(sent)"); 45018316Swollman return -1; 45118316Swollman } 45218316Swollman 45318316Swollman bzero(&router, sizeof(router)); 45418316Swollman router.sin_family = AF_INET; 45518316Swollman#ifdef _HAVE_SIN_LEN 45618316Swollman router.sin_len = sizeof(router); 45718316Swollman#endif 45818316Swollman if (!inet_aton(host, &router.sin_addr)) { 45918316Swollman hp = gethostbyname(host); 46018316Swollman if (hp == 0) { 46118316Swollman herror(host); 46218316Swollman return -1; 46318316Swollman } 46418316Swollman bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr)); 46518316Swollman } 46618316Swollman router.sin_port = htons(RIP_PORT); 46718316Swollman 46818316Swollman if (sendto(s, &omsg_buf, omsg_len, 0, 46918316Swollman (struct sockaddr *)&router, sizeof(router)) < 0) { 47032502Scharnier warn("%s", host); 47118316Swollman return -1; 47218316Swollman } 47318316Swollman 47418316Swollman return 0; 47518316Swollman} 47618316Swollman 47718316Swollman 47818316Swollman/* 47919880Swollman * Convert string to printable characters 48019880Swollman */ 48119880Swollmanstatic char * 48219880Swollmanqstring(u_char *s, int len) 48319880Swollman{ 48419880Swollman static char buf[8*20+1]; 48519880Swollman char *p; 48619880Swollman u_char *s2, c; 48719880Swollman 48819880Swollman 48919880Swollman for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 49019880Swollman c = *s++; 49119880Swollman if (c == '\0') { 49219880Swollman for (s2 = s+1; s2 < &s[len]; s2++) { 49319880Swollman if (*s2 != '\0') 49419880Swollman break; 49519880Swollman } 49619880Swollman if (s2 >= &s[len]) 49719880Swollman goto exit; 49819880Swollman } 49919880Swollman 50019880Swollman if (c >= ' ' && c < 0x7f && c != '\\') { 50119880Swollman *p++ = c; 50219880Swollman continue; 50319880Swollman } 50419880Swollman *p++ = '\\'; 50519880Swollman switch (c) { 50619880Swollman case '\\': 50719880Swollman *p++ = '\\'; 50819880Swollman break; 50919880Swollman case '\n': 51019880Swollman *p++= 'n'; 51119880Swollman break; 51219880Swollman case '\r': 51319880Swollman *p++= 'r'; 51419880Swollman break; 51519880Swollman case '\t': 51619880Swollman *p++ = 't'; 51719880Swollman break; 51819880Swollman case '\b': 51919880Swollman *p++ = 'b'; 52019880Swollman break; 52119880Swollman default: 52219880Swollman p += sprintf(p,"%o",c); 52319880Swollman break; 52419880Swollman } 52519880Swollman } 52619880Swollmanexit: 52719880Swollman *p = '\0'; 52819880Swollman return buf; 52919880Swollman} 53019880Swollman 53119880Swollman 53219880Swollman/* 53318316Swollman * Handle an incoming RIP packet. 53418316Swollman */ 53518316Swollmanstatic void 53618316Swollmanrip_input(struct sockaddr_in *from, 53718316Swollman int size) 53818316Swollman{ 53918316Swollman struct netinfo *n, *lim; 54018316Swollman struct in_addr in; 54118316Swollman char *name; 54218316Swollman char net_buf[80]; 54318316Swollman u_int mask, dmask; 54418316Swollman char *sp; 54518316Swollman int i; 54618316Swollman struct hostent *hp; 54718316Swollman struct netent *np; 54819880Swollman struct netauth *na; 54918316Swollman 55018316Swollman 55118316Swollman if (nflag) { 55218316Swollman printf("%s:", inet_ntoa(from->sin_addr)); 55318316Swollman } else { 55418316Swollman hp = gethostbyaddr((char*)&from->sin_addr, 55518316Swollman sizeof(struct in_addr), AF_INET); 55618316Swollman if (hp == 0) { 55718316Swollman printf("%s:", 55818316Swollman inet_ntoa(from->sin_addr)); 55918316Swollman } else { 56018316Swollman printf("%s (%s):", hp->h_name, 56118316Swollman inet_ntoa(from->sin_addr)); 56218316Swollman } 56318316Swollman } 56418316Swollman if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 56518316Swollman printf("\n unexpected response type %d\n", IMSG.rip_cmd); 56618316Swollman return; 56718316Swollman } 56818316Swollman printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 56918316Swollman (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 57018316Swollman size); 57118316Swollman if (size > MAXPACKETSIZE) { 57218316Swollman if (size > sizeof(imsg_buf) - sizeof(*n)) { 57318316Swollman printf(" at least %d bytes too long\n", 57418316Swollman size-MAXPACKETSIZE); 57518316Swollman size = sizeof(imsg_buf) - sizeof(*n); 57618316Swollman } else { 57718316Swollman printf(" %d bytes too long\n", 57818316Swollman size-MAXPACKETSIZE); 57918316Swollman } 58018316Swollman } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 58118316Swollman printf(" response of bad length=%d\n", size); 58218316Swollman } 58318316Swollman 58418316Swollman n = IMSG.rip_nets; 58518316Swollman lim = (struct netinfo *)((char*)n + size) - 1; 58618316Swollman for (; n <= lim; n++) { 58718316Swollman name = ""; 58818316Swollman if (n->n_family == RIP_AF_INET) { 58918316Swollman in.s_addr = n->n_dst; 59018316Swollman (void)strcpy(net_buf, inet_ntoa(in)); 59118316Swollman 59218316Swollman mask = ntohl(n->n_mask); 59318316Swollman dmask = mask & -mask; 59418316Swollman if (mask != 0) { 59518316Swollman sp = &net_buf[strlen(net_buf)]; 59618316Swollman if (IMSG.rip_vers == RIPv1) { 59718316Swollman (void)sprintf(sp," mask=%#x ? ",mask); 59818316Swollman mask = 0; 59918316Swollman } else if (mask + dmask == 0) { 60018316Swollman for (i = 0; 60118316Swollman (i != 32 60218316Swollman && ((1<<i)&mask) == 0); 60318316Swollman i++) 60418316Swollman continue; 60518316Swollman (void)sprintf(sp, "/%d",32-i); 60618316Swollman } else { 60718316Swollman (void)sprintf(sp," (mask %#x)", mask); 60818316Swollman } 60918316Swollman } 61018316Swollman 61118316Swollman if (!nflag) { 61218316Swollman if (mask == 0) { 61318316Swollman mask = std_mask(in.s_addr); 61418316Swollman if ((ntohl(in.s_addr) & ~mask) != 0) 61518316Swollman mask = 0; 61618316Swollman } 61718316Swollman /* Without a netmask, do not worry about 61818316Swollman * whether the destination is a host or a 61918316Swollman * network. Try both and use the first name 62018316Swollman * we get. 62118316Swollman * 62218316Swollman * If we have a netmask we can make a 62318316Swollman * good guess. 62418316Swollman */ 62518316Swollman if ((in.s_addr & ~mask) == 0) { 62618316Swollman np = getnetbyaddr((long)in.s_addr, 62718316Swollman AF_INET); 62818316Swollman if (np != 0) 62918316Swollman name = np->n_name; 63018316Swollman else if (in.s_addr == 0) 63118316Swollman name = "default"; 63218316Swollman } 63318316Swollman if (name[0] == '\0' 63418316Swollman && ((in.s_addr & ~mask) != 0 63518316Swollman || mask == 0xffffffff)) { 63618316Swollman hp = gethostbyaddr((char*)&in, 63718316Swollman sizeof(in), 63818316Swollman AF_INET); 63918316Swollman if (hp != 0) 64018316Swollman name = hp->h_name; 64118316Swollman } 64218316Swollman } 64318316Swollman 64418316Swollman } else if (n->n_family == RIP_AF_AUTH) { 64519880Swollman na = (struct netauth*)n; 64619880Swollman if (na->a_type == RIP_AUTH_PW 64719880Swollman && n == IMSG.rip_nets) { 64819880Swollman (void)printf(" Password Authentication:" 64919880Swollman " \"%s\"\n", 65019880Swollman qstring(na->au.au_pw, 65119880Swollman RIP_AUTH_PW_LEN)); 65219880Swollman continue; 65319880Swollman } 65419880Swollman 65519880Swollman if (na->a_type == RIP_AUTH_MD5 65619880Swollman && n == IMSG.rip_nets) { 65719880Swollman (void)printf(" MD5 Authentication" 65819880Swollman " len=%d KeyID=%d" 65919880Swollman " seqno=%d" 66019880Swollman " rsvd=%#x,%#x\n", 66119880Swollman na->au.a_md5.md5_pkt_len, 66219880Swollman na->au.a_md5.md5_keyid, 66319880Swollman na->au.a_md5.md5_seqno, 66419880Swollman na->au.a_md5.rsvd[0], 66519880Swollman na->au.a_md5.rsvd[1]); 66619880Swollman continue; 66719880Swollman } 66819880Swollman (void)printf(" Authentication type %d: ", 66919880Swollman ntohs(na->a_type)); 67019880Swollman for (i = 0; i < sizeof(na->au.au_pw); i++) 67119880Swollman (void)printf("%02x ", na->au.au_pw[i]); 67218316Swollman putc('\n', stdout); 67318316Swollman continue; 67418316Swollman 67518316Swollman } else { 67618316Swollman (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 67718316Swollman ntohs(n->n_family), 67818316Swollman (char)(n->n_dst >> 24), 67918316Swollman (char)(n->n_dst >> 16), 68018316Swollman (char)(n->n_dst >> 8), 68118316Swollman (char)n->n_dst); 68218316Swollman } 68318316Swollman 68418316Swollman (void)printf(" %-18s metric %2d %-10s", 68518316Swollman net_buf, ntohl(n->n_metric), name); 68618316Swollman 68718316Swollman if (n->n_nhop != 0) { 68818316Swollman in.s_addr = n->n_nhop; 68918316Swollman if (nflag) 69018316Swollman hp = 0; 69118316Swollman else 69218316Swollman hp = gethostbyaddr((char*)&in, sizeof(in), 69318316Swollman AF_INET); 69418316Swollman (void)printf(" nhop=%-15s%s", 69518316Swollman (hp != 0) ? hp->h_name : inet_ntoa(in), 69618316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 69718316Swollman } 69818316Swollman if (n->n_tag != 0) 69918316Swollman (void)printf(" tag=%#x%s", n->n_tag, 70018316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 70118316Swollman putc('\n', stdout); 70218316Swollman } 70318316Swollman} 70418316Swollman 70518316Swollman 70618316Swollman/* Return the classical netmask for an IP address. 70718316Swollman */ 70818316Swollmanstatic u_int 70918316Swollmanstd_mask(u_int addr) /* in network order */ 71018316Swollman{ 71118316Swollman NTOHL(addr); /* was a host, not a network */ 71218316Swollman 71318316Swollman if (addr == 0) /* default route has mask 0 */ 71418316Swollman return 0; 71518316Swollman if (IN_CLASSA(addr)) 71618316Swollman return IN_CLASSA_NET; 71718316Swollman if (IN_CLASSB(addr)) 71818316Swollman return IN_CLASSB_NET; 71918316Swollman return IN_CLASSC_NET; 72018316Swollman} 72118316Swollman 72218316Swollman 72318316Swollman/* get a network number as a name or a number, with an optional "/xx" 72418316Swollman * netmask. 72518316Swollman */ 72618316Swollmanstatic int /* 0=bad */ 72718316Swollmangetnet(char *name, 72818316Swollman struct netinfo *rt) 72918316Swollman{ 73018316Swollman int i; 73118316Swollman struct netent *nentp; 73218316Swollman u_int mask; 73318316Swollman struct in_addr in; 73418316Swollman char hname[MAXHOSTNAMELEN+1]; 73518316Swollman char *mname, *p; 73618316Swollman 73718316Swollman 73818316Swollman /* Detect and separate "1.2.3.4/24" 73918316Swollman */ 74018316Swollman if (0 != (mname = rindex(name,'/'))) { 74118316Swollman i = (int)(mname - name); 74218316Swollman if (i > sizeof(hname)-1) /* name too long */ 74318316Swollman return 0; 74418316Swollman bcopy(name, hname, i); 74518316Swollman hname[i] = '\0'; 74618316Swollman mname++; 74718316Swollman name = hname; 74818316Swollman } 74918316Swollman 75018316Swollman nentp = getnetbyname(name); 75118316Swollman if (nentp != 0) { 75218316Swollman in.s_addr = nentp->n_net; 75318316Swollman } else if (inet_aton(name, &in) == 1) { 75418316Swollman NTOHL(in.s_addr); 75518316Swollman } else { 75618316Swollman return 0; 75718316Swollman } 75818316Swollman 75918316Swollman if (mname == 0) { 76018316Swollman mask = std_mask(in.s_addr); 76118316Swollman if ((~mask & in.s_addr) != 0) 76218316Swollman mask = 0xffffffff; 76318316Swollman } else { 76418316Swollman mask = (u_int)strtoul(mname, &p, 0); 76518316Swollman if (*p != '\0' || mask > 32) 76618316Swollman return 0; 76718316Swollman mask = 0xffffffff << (32-mask); 76818316Swollman } 76918316Swollman 77018316Swollman rt->n_dst = htonl(in.s_addr); 77118316Swollman rt->n_family = RIP_AF_INET; 77218316Swollman rt->n_mask = htonl(mask); 77318316Swollman return 1; 77418316Swollman} 77519880Swollman 77619880Swollman 77719880Swollman/* strtok(), but honoring backslash 77819880Swollman */ 77919880Swollmanstatic int /* -1=bad */ 78019880Swollmanparse_quote(char **linep, 78119880Swollman char *delims, 78219880Swollman char *delimp, 78319880Swollman char *buf, 78419880Swollman int lim) 78519880Swollman{ 78619880Swollman char c, *pc, *p; 78719880Swollman 78819880Swollman 78919880Swollman pc = *linep; 79019880Swollman if (*pc == '\0') 79119880Swollman return -1; 79219880Swollman 79319880Swollman for (;;) { 79419880Swollman if (lim == 0) 79519880Swollman return -1; 79619880Swollman c = *pc++; 79719880Swollman if (c == '\0') 79819880Swollman break; 79919880Swollman 80019880Swollman if (c == '\\' && pc != '\0') { 80119880Swollman if ((c = *pc++) == 'n') { 80219880Swollman c = '\n'; 80319880Swollman } else if (c == 'r') { 80419880Swollman c = '\r'; 80519880Swollman } else if (c == 't') { 80619880Swollman c = '\t'; 80719880Swollman } else if (c == 'b') { 80819880Swollman c = '\b'; 80919880Swollman } else if (c >= '0' && c <= '7') { 81019880Swollman c -= '0'; 81119880Swollman if (*pc >= '0' && *pc <= '7') { 81219880Swollman c = (c<<3)+(*pc++ - '0'); 81319880Swollman if (*pc >= '0' && *pc <= '7') 81419880Swollman c = (c<<3)+(*pc++ - '0'); 81519880Swollman } 81619880Swollman } 81719880Swollman 81819880Swollman } else { 81919880Swollman for (p = delims; *p != '\0'; ++p) { 82019880Swollman if (*p == c) 82119880Swollman goto exit; 82219880Swollman } 82319880Swollman } 82419880Swollman 82519880Swollman *buf++ = c; 82619880Swollman --lim; 82719880Swollman } 82819880Swollmanexit: 82919880Swollman if (delimp != 0) 83019880Swollman *delimp = c; 83119880Swollman *linep = pc-1; 83219880Swollman if (lim != 0) 83319880Swollman *buf = '\0'; 83419880Swollman return 0; 83519880Swollman} 836