rtquery.c revision 24359
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 3418316Swollmanchar copyright[] = 3518316Swollman"@(#) Copyright (c) 1982, 1986, 1993\n\ 3618316Swollman The Regents of the University of California. All rights reserved.\n"; 3718316Swollman 3818316Swollman#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) 3918316Swollmanstatic char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93"; 4018316Swollman#elif defined(__NetBSD__) 4118316Swollmanstatic char rcsid[] = "$NetBSD$"; 4218316Swollman#endif 4318316Swollman 4418316Swollman#include <sys/param.h> 4518316Swollman#include <sys/protosw.h> 4618316Swollman#include <sys/socket.h> 4718316Swollman#include <sys/time.h> 4818316Swollman#include <netinet/in.h> 4918316Swollman#define RIPVERSION RIPv2 5018316Swollman#include <protocols/routed.h> 5118316Swollman#include <arpa/inet.h> 5218316Swollman#include <netdb.h> 5318316Swollman#include <errno.h> 5418316Swollman#include <unistd.h> 5518316Swollman#include <stdio.h> 5618316Swollman#include <stdlib.h> 5718316Swollman#include <string.h> 5818316Swollman#ifdef sgi 5918316Swollman#include <strings.h> 6018316Swollman#include <bstring.h> 6118316Swollman#endif 6218316Swollman 6318316Swollman#ifndef sgi 6418316Swollman#define _HAVE_SIN_LEN 6518316Swollman#endif 6618316Swollman 6719885Swollman#include <md5.h> 6818316Swollman#define WTIME 15 /* Time to wait for all responses */ 6918316Swollman#define STIME (250*1000) /* usec to wait for another response */ 7018316Swollman 7118316Swollmanint s; 7218316Swollman 7318316Swollmanchar *pgmname; 7418316Swollman 7518316Swollmanunion { 7618316Swollman struct rip rip; 7718316Swollman char packet[MAXPACKETSIZE+MAXPATHLEN]; 7818316Swollman} omsg_buf; 7918316Swollman#define OMSG omsg_buf.rip 8018316Swollmanint omsg_len = sizeof(struct rip); 8118316Swollman 8218316Swollmanunion { 8318316Swollman struct rip rip; 8418316Swollman char packet[MAXPACKETSIZE+1024]; 8518316Swollman } imsg_buf; 8618316Swollman#define IMSG imsg_buf.rip 8718316Swollman 8818316Swollmanint nflag; /* numbers, no names */ 8918316Swollmanint pflag; /* play the `gated` game */ 9018316Swollmanint ripv2 = 1; /* use RIP version 2 */ 9118316Swollmanint wtime = WTIME; 9218316Swollmanint rflag; /* 1=ask about a particular route */ 9319880Swollmanint trace, not_trace; /* send trace command or not */ 9419880Swollmanint auth_type = RIP_AUTH_NONE; 9519880Swollmanchar passwd[RIP_AUTH_PW_LEN]; 9619880Swollmanu_long keyid; 9718316Swollman 9818316Swollmanstruct timeval sent; /* when query sent */ 9918316Swollman 10018316Swollmanstatic void rip_input(struct sockaddr_in*, int); 10118316Swollmanstatic int out(char *); 10218316Swollmanstatic void trace_loop(char *argv[]); 10318316Swollmanstatic void query_loop(char *argv[], int); 10418316Swollmanstatic int getnet(char *, struct netinfo *); 10518316Swollmanstatic u_int std_mask(u_int); 10619880Swollmanstatic int parse_quote(char **, char *, char *, char *, int); 10718316Swollman 10818316Swollman 10920609Swollmanvoid 11018316Swollmanmain(int argc, 11118316Swollman char *argv[]) 11218316Swollman{ 11318316Swollman int ch, bsize; 11419880Swollman char *p, *options, *value, delim; 11518316Swollman 11618316Swollman OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 11718316Swollman OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 11818316Swollman OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 11918316Swollman 12018316Swollman pgmname = argv[0]; 12124359Simp while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) 12218316Swollman switch (ch) { 12318316Swollman case 'n': 12418316Swollman not_trace = 1; 12518316Swollman nflag = 1; 12618316Swollman break; 12718316Swollman 12818316Swollman case 'p': 12918316Swollman not_trace = 1; 13018316Swollman pflag = 1; 13118316Swollman break; 13218316Swollman 13318316Swollman case '1': 13418316Swollman ripv2 = 0; 13518316Swollman break; 13618316Swollman 13718316Swollman case 'w': 13818316Swollman not_trace = 1; 13918316Swollman wtime = (int)strtoul(optarg, &p, 0); 14018316Swollman if (*p != '\0' 14118316Swollman || wtime <= 0) 14218316Swollman goto usage; 14318316Swollman break; 14418316Swollman 14518316Swollman case 'r': 14618316Swollman not_trace = 1; 14718316Swollman if (rflag) 14818316Swollman goto usage; 14918316Swollman rflag = getnet(optarg, &OMSG.rip_nets[0]); 15018316Swollman if (!rflag) { 15118316Swollman struct hostent *hp = gethostbyname(optarg); 15218316Swollman if (hp == 0) { 15318316Swollman fprintf(stderr, "%s: %s:", 15418316Swollman pgmname, 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) { 24518316Swollmanusage: fprintf(stderr, "%s: [-np1v] [-r tgt_rt] [-w wtime]" 24619880Swollman " [-a type=passwd] host1 [host2 ...]\n" 24720609Swollman "or\t-t {on=filename|more|off|dump}" 24819880Swollman " host1 [host2 ...]\n", 24918316Swollman pgmname); 25018316Swollman exit(1); 25118316Swollman } 25218316Swollman 25318316Swollman s = socket(AF_INET, SOCK_DGRAM, 0); 25418316Swollman if (s < 0) { 25518316Swollman perror("socket"); 25618316Swollman exit(2); 25718316Swollman } 25818316Swollman 25918316Swollman /* be prepared to receive a lot of routes */ 26018316Swollman for (bsize = 127*1024; ; bsize -= 1024) { 26118316Swollman if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 26218316Swollman &bsize, sizeof(bsize)) == 0) 26318316Swollman break; 26418316Swollman if (bsize <= 4*1024) { 26518316Swollman perror("setsockopt SO_RCVBUF"); 26618316Swollman break; 26718316Swollman } 26818316Swollman } 26918316Swollman 27018316Swollman if (trace) 27118316Swollman trace_loop(argv); 27218316Swollman else 27318316Swollman query_loop(argv, argc); 27418316Swollman /* NOTREACHED */ 27518316Swollman} 27618316Swollman 27718316Swollman 27818316Swollman/* tell the target hosts about tracing 27918316Swollman */ 28018316Swollmanstatic void 28118316Swollmantrace_loop(char *argv[]) 28218316Swollman{ 28318316Swollman struct sockaddr_in myaddr; 28418316Swollman int res; 28518316Swollman 28618316Swollman if (geteuid() != 0) { 28718316Swollman (void)fprintf(stderr, "-t requires UID 0\n"); 28818316Swollman exit(1); 28918316Swollman } 29018316Swollman 29118316Swollman if (ripv2) { 29218316Swollman OMSG.rip_vers = RIPv2; 29318316Swollman } else { 29418316Swollman OMSG.rip_vers = RIPv1; 29518316Swollman } 29618316Swollman 29718316Swollman bzero(&myaddr, sizeof(myaddr)); 29818316Swollman myaddr.sin_family = AF_INET; 29918316Swollman#ifdef _HAVE_SIN_LEN 30018316Swollman myaddr.sin_len = sizeof(myaddr); 30118316Swollman#endif 30218316Swollman myaddr.sin_port = htons(IPPORT_RESERVED-1); 30318316Swollman while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 30418316Swollman if (errno != EADDRINUSE 30518316Swollman || myaddr.sin_port == 0) { 30618316Swollman perror("bind"); 30718316Swollman exit(2); 30818316Swollman } 30918316Swollman myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 31018316Swollman } 31118316Swollman 31218316Swollman res = 1; 31318316Swollman while (*argv != 0) { 31418316Swollman if (out(*argv++) <= 0) 31518316Swollman res = 0; 31618316Swollman } 31718316Swollman exit(res); 31818316Swollman} 31918316Swollman 32018316Swollman 32118316Swollman/* query all of the listed hosts 32218316Swollman */ 32318316Swollmanstatic void 32418316Swollmanquery_loop(char *argv[], int argc) 32518316Swollman{ 32619880Swollman# define NA0 (OMSG.rip_auths[0]) 32719880Swollman# define NA2 (OMSG.rip_auths[2]) 32818316Swollman struct seen { 32918316Swollman struct seen *next; 33018316Swollman struct in_addr addr; 33118316Swollman } *seen, *sp; 33218316Swollman int answered = 0; 33318316Swollman int cc; 33418316Swollman fd_set bits; 33518316Swollman struct timeval now, delay; 33618316Swollman struct sockaddr_in from; 33718316Swollman int fromlen; 33819880Swollman MD5_CTX md5_ctx; 33918316Swollman 34018316Swollman 34118316Swollman OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 34218316Swollman if (ripv2) { 34318316Swollman OMSG.rip_vers = RIPv2; 34419880Swollman if (auth_type == RIP_AUTH_PW) { 34519880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 34619880Swollman NA0.a_family = RIP_AF_AUTH; 34719880Swollman NA0.a_type = RIP_AUTH_PW; 34819880Swollman bcopy(passwd, NA0.au.au_pw, 34919880Swollman RIP_AUTH_PW_LEN); 35019880Swollman omsg_len += sizeof(OMSG.rip_nets[0]); 35119880Swollman 35219880Swollman } else if (auth_type == RIP_AUTH_MD5) { 35319880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 35419880Swollman NA0.a_family = RIP_AF_AUTH; 35519880Swollman NA0.a_type = RIP_AUTH_MD5; 35619880Swollman NA0.au.a_md5.md5_keyid = (int8_t)keyid; 35719880Swollman NA0.au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN; 35819880Swollman NA0.au.a_md5.md5_seqno = 0; 35919880Swollman NA0.au.a_md5.md5_pkt_len = sizeof(OMSG.rip_nets[1]); 36019880Swollman NA2.a_family = RIP_AF_AUTH; 36119880Swollman NA2.a_type = 1; 36219880Swollman bcopy(passwd, NA2.au.au_pw, sizeof(NA2.au.au_pw)); 36319880Swollman MD5Init(&md5_ctx); 36419880Swollman MD5Update(&md5_ctx, (u_char *)&NA0, 36519880Swollman (char *)(&NA2+1) - (char *)&NA0); 36619880Swollman MD5Final(NA2.au.au_pw, &md5_ctx); 36719880Swollman omsg_len += 2*sizeof(OMSG.rip_nets[0]); 36819880Swollman } 36919880Swollman 37018316Swollman } else { 37118316Swollman OMSG.rip_vers = RIPv1; 37218316Swollman OMSG.rip_nets[0].n_mask = 0; 37318316Swollman } 37418316Swollman 37518316Swollman /* ask the first (valid) host */ 37618316Swollman seen = 0; 37718316Swollman while (0 > out(*argv++)) { 37818316Swollman if (*argv == 0) 37918316Swollman exit(-1); 38018316Swollman answered++; 38118316Swollman } 38218316Swollman 38318316Swollman FD_ZERO(&bits); 38418316Swollman for (;;) { 38518316Swollman FD_SET(s, &bits); 38618316Swollman delay.tv_sec = 0; 38718316Swollman delay.tv_usec = STIME; 38818316Swollman cc = select(s+1, &bits, 0,0, &delay); 38918316Swollman if (cc > 0) { 39018316Swollman fromlen = sizeof(from); 39118316Swollman cc = recvfrom(s, imsg_buf.packet, 39218316Swollman sizeof(imsg_buf.packet), 0, 39318316Swollman (struct sockaddr *)&from, &fromlen); 39418316Swollman if (cc < 0) { 39518316Swollman perror("recvfrom"); 39618316Swollman exit(1); 39718316Swollman } 39818316Swollman /* count the distinct responding hosts. 39918316Swollman * You cannot match responding hosts with 40018316Swollman * addresses to which queries were transmitted, 40118316Swollman * because a router might respond with a 40218316Swollman * different source address. 40318316Swollman */ 40418316Swollman for (sp = seen; sp != 0; sp = sp->next) { 40518316Swollman if (sp->addr.s_addr == from.sin_addr.s_addr) 40618316Swollman break; 40718316Swollman } 40818316Swollman if (sp == 0) { 40918316Swollman sp = malloc(sizeof(*sp)); 41018316Swollman sp->addr = from.sin_addr; 41118316Swollman sp->next = seen; 41218316Swollman seen = sp; 41318316Swollman answered++; 41418316Swollman } 41518316Swollman 41618316Swollman rip_input(&from, cc); 41718316Swollman continue; 41818316Swollman } 41918316Swollman 42018316Swollman if (cc < 0) { 42118316Swollman if ( errno == EINTR) 42218316Swollman continue; 42318316Swollman perror("select"); 42418316Swollman exit(1); 42518316Swollman } 42618316Swollman 42718316Swollman /* After a pause in responses, probe another host. 42818316Swollman * This reduces the intermingling of answers. 42918316Swollman */ 43018316Swollman while (*argv != 0 && 0 > out(*argv++)) 43118316Swollman answered++; 43218316Swollman 43318316Swollman /* continue until no more packets arrive 43418316Swollman * or we have heard from all hosts 43518316Swollman */ 43618316Swollman if (answered >= argc) 43718316Swollman break; 43818316Swollman 43918316Swollman /* or until we have waited a long time 44018316Swollman */ 44118316Swollman if (gettimeofday(&now, 0) < 0) { 44218316Swollman perror("gettimeofday(now)"); 44318316Swollman exit(1); 44418316Swollman } 44518316Swollman if (sent.tv_sec + wtime <= now.tv_sec) 44618316Swollman break; 44718316Swollman } 44818316Swollman 44918316Swollman /* fail if there was no answer */ 45018316Swollman exit (answered >= argc ? 0 : 1); 45118316Swollman} 45218316Swollman 45318316Swollman 45419880Swollman/* send to one host 45518316Swollman */ 45618316Swollmanstatic int 45718316Swollmanout(char *host) 45818316Swollman{ 45918316Swollman struct sockaddr_in router; 46018316Swollman struct hostent *hp; 46118316Swollman 46218316Swollman if (gettimeofday(&sent, 0) < 0) { 46318316Swollman perror("gettimeofday(sent)"); 46418316Swollman return -1; 46518316Swollman } 46618316Swollman 46718316Swollman bzero(&router, sizeof(router)); 46818316Swollman router.sin_family = AF_INET; 46918316Swollman#ifdef _HAVE_SIN_LEN 47018316Swollman router.sin_len = sizeof(router); 47118316Swollman#endif 47218316Swollman if (!inet_aton(host, &router.sin_addr)) { 47318316Swollman hp = gethostbyname(host); 47418316Swollman if (hp == 0) { 47518316Swollman herror(host); 47618316Swollman return -1; 47718316Swollman } 47818316Swollman bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr)); 47918316Swollman } 48018316Swollman router.sin_port = htons(RIP_PORT); 48118316Swollman 48218316Swollman if (sendto(s, &omsg_buf, omsg_len, 0, 48318316Swollman (struct sockaddr *)&router, sizeof(router)) < 0) { 48418316Swollman perror(host); 48518316Swollman return -1; 48618316Swollman } 48718316Swollman 48818316Swollman return 0; 48918316Swollman} 49018316Swollman 49118316Swollman 49218316Swollman/* 49319880Swollman * Convert string to printable characters 49419880Swollman */ 49519880Swollmanstatic char * 49619880Swollmanqstring(u_char *s, int len) 49719880Swollman{ 49819880Swollman static char buf[8*20+1]; 49919880Swollman char *p; 50019880Swollman u_char *s2, c; 50119880Swollman 50219880Swollman 50319880Swollman for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 50419880Swollman c = *s++; 50519880Swollman if (c == '\0') { 50619880Swollman for (s2 = s+1; s2 < &s[len]; s2++) { 50719880Swollman if (*s2 != '\0') 50819880Swollman break; 50919880Swollman } 51019880Swollman if (s2 >= &s[len]) 51119880Swollman goto exit; 51219880Swollman } 51319880Swollman 51419880Swollman if (c >= ' ' && c < 0x7f && c != '\\') { 51519880Swollman *p++ = c; 51619880Swollman continue; 51719880Swollman } 51819880Swollman *p++ = '\\'; 51919880Swollman switch (c) { 52019880Swollman case '\\': 52119880Swollman *p++ = '\\'; 52219880Swollman break; 52319880Swollman case '\n': 52419880Swollman *p++= 'n'; 52519880Swollman break; 52619880Swollman case '\r': 52719880Swollman *p++= 'r'; 52819880Swollman break; 52919880Swollman case '\t': 53019880Swollman *p++ = 't'; 53119880Swollman break; 53219880Swollman case '\b': 53319880Swollman *p++ = 'b'; 53419880Swollman break; 53519880Swollman default: 53619880Swollman p += sprintf(p,"%o",c); 53719880Swollman break; 53819880Swollman } 53919880Swollman } 54019880Swollmanexit: 54119880Swollman *p = '\0'; 54219880Swollman return buf; 54319880Swollman} 54419880Swollman 54519880Swollman 54619880Swollman/* 54718316Swollman * Handle an incoming RIP packet. 54818316Swollman */ 54918316Swollmanstatic void 55018316Swollmanrip_input(struct sockaddr_in *from, 55118316Swollman int size) 55218316Swollman{ 55318316Swollman struct netinfo *n, *lim; 55418316Swollman struct in_addr in; 55518316Swollman char *name; 55618316Swollman char net_buf[80]; 55718316Swollman u_int mask, dmask; 55818316Swollman char *sp; 55918316Swollman int i; 56018316Swollman struct hostent *hp; 56118316Swollman struct netent *np; 56219880Swollman struct netauth *na; 56318316Swollman 56418316Swollman 56518316Swollman if (nflag) { 56618316Swollman printf("%s:", inet_ntoa(from->sin_addr)); 56718316Swollman } else { 56818316Swollman hp = gethostbyaddr((char*)&from->sin_addr, 56918316Swollman sizeof(struct in_addr), AF_INET); 57018316Swollman if (hp == 0) { 57118316Swollman printf("%s:", 57218316Swollman inet_ntoa(from->sin_addr)); 57318316Swollman } else { 57418316Swollman printf("%s (%s):", hp->h_name, 57518316Swollman inet_ntoa(from->sin_addr)); 57618316Swollman } 57718316Swollman } 57818316Swollman if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 57918316Swollman printf("\n unexpected response type %d\n", IMSG.rip_cmd); 58018316Swollman return; 58118316Swollman } 58218316Swollman printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 58318316Swollman (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 58418316Swollman size); 58518316Swollman if (size > MAXPACKETSIZE) { 58618316Swollman if (size > sizeof(imsg_buf) - sizeof(*n)) { 58718316Swollman printf(" at least %d bytes too long\n", 58818316Swollman size-MAXPACKETSIZE); 58918316Swollman size = sizeof(imsg_buf) - sizeof(*n); 59018316Swollman } else { 59118316Swollman printf(" %d bytes too long\n", 59218316Swollman size-MAXPACKETSIZE); 59318316Swollman } 59418316Swollman } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 59518316Swollman printf(" response of bad length=%d\n", size); 59618316Swollman } 59718316Swollman 59818316Swollman n = IMSG.rip_nets; 59918316Swollman lim = (struct netinfo *)((char*)n + size) - 1; 60018316Swollman for (; n <= lim; n++) { 60118316Swollman name = ""; 60218316Swollman if (n->n_family == RIP_AF_INET) { 60318316Swollman in.s_addr = n->n_dst; 60418316Swollman (void)strcpy(net_buf, inet_ntoa(in)); 60518316Swollman 60618316Swollman mask = ntohl(n->n_mask); 60718316Swollman dmask = mask & -mask; 60818316Swollman if (mask != 0) { 60918316Swollman sp = &net_buf[strlen(net_buf)]; 61018316Swollman if (IMSG.rip_vers == RIPv1) { 61118316Swollman (void)sprintf(sp," mask=%#x ? ",mask); 61218316Swollman mask = 0; 61318316Swollman } else if (mask + dmask == 0) { 61418316Swollman for (i = 0; 61518316Swollman (i != 32 61618316Swollman && ((1<<i)&mask) == 0); 61718316Swollman i++) 61818316Swollman continue; 61918316Swollman (void)sprintf(sp, "/%d",32-i); 62018316Swollman } else { 62118316Swollman (void)sprintf(sp," (mask %#x)", mask); 62218316Swollman } 62318316Swollman } 62418316Swollman 62518316Swollman if (!nflag) { 62618316Swollman if (mask == 0) { 62718316Swollman mask = std_mask(in.s_addr); 62818316Swollman if ((ntohl(in.s_addr) & ~mask) != 0) 62918316Swollman mask = 0; 63018316Swollman } 63118316Swollman /* Without a netmask, do not worry about 63218316Swollman * whether the destination is a host or a 63318316Swollman * network. Try both and use the first name 63418316Swollman * we get. 63518316Swollman * 63618316Swollman * If we have a netmask we can make a 63718316Swollman * good guess. 63818316Swollman */ 63918316Swollman if ((in.s_addr & ~mask) == 0) { 64018316Swollman np = getnetbyaddr((long)in.s_addr, 64118316Swollman AF_INET); 64218316Swollman if (np != 0) 64318316Swollman name = np->n_name; 64418316Swollman else if (in.s_addr == 0) 64518316Swollman name = "default"; 64618316Swollman } 64718316Swollman if (name[0] == '\0' 64818316Swollman && ((in.s_addr & ~mask) != 0 64918316Swollman || mask == 0xffffffff)) { 65018316Swollman hp = gethostbyaddr((char*)&in, 65118316Swollman sizeof(in), 65218316Swollman AF_INET); 65318316Swollman if (hp != 0) 65418316Swollman name = hp->h_name; 65518316Swollman } 65618316Swollman } 65718316Swollman 65818316Swollman } else if (n->n_family == RIP_AF_AUTH) { 65919880Swollman na = (struct netauth*)n; 66019880Swollman if (na->a_type == RIP_AUTH_PW 66119880Swollman && n == IMSG.rip_nets) { 66219880Swollman (void)printf(" Password Authentication:" 66319880Swollman " \"%s\"\n", 66419880Swollman qstring(na->au.au_pw, 66519880Swollman RIP_AUTH_PW_LEN)); 66619880Swollman continue; 66719880Swollman } 66819880Swollman 66919880Swollman if (na->a_type == RIP_AUTH_MD5 67019880Swollman && n == IMSG.rip_nets) { 67119880Swollman (void)printf(" MD5 Authentication" 67219880Swollman " len=%d KeyID=%d" 67319880Swollman " seqno=%d" 67419880Swollman " rsvd=%#x,%#x\n", 67519880Swollman na->au.a_md5.md5_pkt_len, 67619880Swollman na->au.a_md5.md5_keyid, 67719880Swollman na->au.a_md5.md5_seqno, 67819880Swollman na->au.a_md5.rsvd[0], 67919880Swollman na->au.a_md5.rsvd[1]); 68019880Swollman continue; 68119880Swollman } 68219880Swollman (void)printf(" Authentication type %d: ", 68319880Swollman ntohs(na->a_type)); 68419880Swollman for (i = 0; i < sizeof(na->au.au_pw); i++) 68519880Swollman (void)printf("%02x ", na->au.au_pw[i]); 68618316Swollman putc('\n', stdout); 68718316Swollman continue; 68818316Swollman 68918316Swollman } else { 69018316Swollman (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 69118316Swollman ntohs(n->n_family), 69218316Swollman (char)(n->n_dst >> 24), 69318316Swollman (char)(n->n_dst >> 16), 69418316Swollman (char)(n->n_dst >> 8), 69518316Swollman (char)n->n_dst); 69618316Swollman } 69718316Swollman 69818316Swollman (void)printf(" %-18s metric %2d %-10s", 69918316Swollman net_buf, ntohl(n->n_metric), name); 70018316Swollman 70118316Swollman if (n->n_nhop != 0) { 70218316Swollman in.s_addr = n->n_nhop; 70318316Swollman if (nflag) 70418316Swollman hp = 0; 70518316Swollman else 70618316Swollman hp = gethostbyaddr((char*)&in, sizeof(in), 70718316Swollman AF_INET); 70818316Swollman (void)printf(" nhop=%-15s%s", 70918316Swollman (hp != 0) ? hp->h_name : inet_ntoa(in), 71018316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 71118316Swollman } 71218316Swollman if (n->n_tag != 0) 71318316Swollman (void)printf(" tag=%#x%s", n->n_tag, 71418316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 71518316Swollman putc('\n', stdout); 71618316Swollman } 71718316Swollman} 71818316Swollman 71918316Swollman 72018316Swollman/* Return the classical netmask for an IP address. 72118316Swollman */ 72218316Swollmanstatic u_int 72318316Swollmanstd_mask(u_int addr) /* in network order */ 72418316Swollman{ 72518316Swollman NTOHL(addr); /* was a host, not a network */ 72618316Swollman 72718316Swollman if (addr == 0) /* default route has mask 0 */ 72818316Swollman return 0; 72918316Swollman if (IN_CLASSA(addr)) 73018316Swollman return IN_CLASSA_NET; 73118316Swollman if (IN_CLASSB(addr)) 73218316Swollman return IN_CLASSB_NET; 73318316Swollman return IN_CLASSC_NET; 73418316Swollman} 73518316Swollman 73618316Swollman 73718316Swollman/* get a network number as a name or a number, with an optional "/xx" 73818316Swollman * netmask. 73918316Swollman */ 74018316Swollmanstatic int /* 0=bad */ 74118316Swollmangetnet(char *name, 74218316Swollman struct netinfo *rt) 74318316Swollman{ 74418316Swollman int i; 74518316Swollman struct netent *nentp; 74618316Swollman u_int mask; 74718316Swollman struct in_addr in; 74818316Swollman char hname[MAXHOSTNAMELEN+1]; 74918316Swollman char *mname, *p; 75018316Swollman 75118316Swollman 75218316Swollman /* Detect and separate "1.2.3.4/24" 75318316Swollman */ 75418316Swollman if (0 != (mname = rindex(name,'/'))) { 75518316Swollman i = (int)(mname - name); 75618316Swollman if (i > sizeof(hname)-1) /* name too long */ 75718316Swollman return 0; 75818316Swollman bcopy(name, hname, i); 75918316Swollman hname[i] = '\0'; 76018316Swollman mname++; 76118316Swollman name = hname; 76218316Swollman } 76318316Swollman 76418316Swollman nentp = getnetbyname(name); 76518316Swollman if (nentp != 0) { 76618316Swollman in.s_addr = nentp->n_net; 76718316Swollman } else if (inet_aton(name, &in) == 1) { 76818316Swollman NTOHL(in.s_addr); 76918316Swollman } else { 77018316Swollman return 0; 77118316Swollman } 77218316Swollman 77318316Swollman if (mname == 0) { 77418316Swollman mask = std_mask(in.s_addr); 77518316Swollman if ((~mask & in.s_addr) != 0) 77618316Swollman mask = 0xffffffff; 77718316Swollman } else { 77818316Swollman mask = (u_int)strtoul(mname, &p, 0); 77918316Swollman if (*p != '\0' || mask > 32) 78018316Swollman return 0; 78118316Swollman mask = 0xffffffff << (32-mask); 78218316Swollman } 78318316Swollman 78418316Swollman rt->n_dst = htonl(in.s_addr); 78518316Swollman rt->n_family = RIP_AF_INET; 78618316Swollman rt->n_mask = htonl(mask); 78718316Swollman return 1; 78818316Swollman} 78919880Swollman 79019880Swollman 79119880Swollman/* strtok(), but honoring backslash 79219880Swollman */ 79319880Swollmanstatic int /* -1=bad */ 79419880Swollmanparse_quote(char **linep, 79519880Swollman char *delims, 79619880Swollman char *delimp, 79719880Swollman char *buf, 79819880Swollman int lim) 79919880Swollman{ 80019880Swollman char c, *pc, *p; 80119880Swollman 80219880Swollman 80319880Swollman pc = *linep; 80419880Swollman if (*pc == '\0') 80519880Swollman return -1; 80619880Swollman 80719880Swollman for (;;) { 80819880Swollman if (lim == 0) 80919880Swollman return -1; 81019880Swollman c = *pc++; 81119880Swollman if (c == '\0') 81219880Swollman break; 81319880Swollman 81419880Swollman if (c == '\\' && pc != '\0') { 81519880Swollman if ((c = *pc++) == 'n') { 81619880Swollman c = '\n'; 81719880Swollman } else if (c == 'r') { 81819880Swollman c = '\r'; 81919880Swollman } else if (c == 't') { 82019880Swollman c = '\t'; 82119880Swollman } else if (c == 'b') { 82219880Swollman c = '\b'; 82319880Swollman } else if (c >= '0' && c <= '7') { 82419880Swollman c -= '0'; 82519880Swollman if (*pc >= '0' && *pc <= '7') { 82619880Swollman c = (c<<3)+(*pc++ - '0'); 82719880Swollman if (*pc >= '0' && *pc <= '7') 82819880Swollman c = (c<<3)+(*pc++ - '0'); 82919880Swollman } 83019880Swollman } 83119880Swollman 83219880Swollman } else { 83319880Swollman for (p = delims; *p != '\0'; ++p) { 83419880Swollman if (*p == c) 83519880Swollman goto exit; 83619880Swollman } 83719880Swollman } 83819880Swollman 83919880Swollman *buf++ = c; 84019880Swollman --lim; 84119880Swollman } 84219880Swollmanexit: 84319880Swollman if (delimp != 0) 84419880Swollman *delimp = c; 84519880Swollman *linep = pc-1; 84619880Swollman if (lim != 0) 84719880Swollman *buf = '\0'; 84819880Swollman return 0; 84919880Swollman} 850