rtquery.c revision 19880
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#ident "$Revision: 1.9 $" 4418316Swollman 4518316Swollman#include <sys/param.h> 4618316Swollman#include <sys/protosw.h> 4718316Swollman#include <sys/socket.h> 4818316Swollman#include <sys/time.h> 4918316Swollman#include <netinet/in.h> 5018316Swollman#define RIPVERSION RIPv2 5118316Swollman#include <protocols/routed.h> 5218316Swollman#include <arpa/inet.h> 5318316Swollman#include <netdb.h> 5418316Swollman#include <errno.h> 5518316Swollman#include <unistd.h> 5618316Swollman#include <stdio.h> 5718316Swollman#include <stdlib.h> 5818316Swollman#include <string.h> 5918316Swollman#ifdef sgi 6018316Swollman#include <strings.h> 6118316Swollman#include <bstring.h> 6218316Swollman#endif 6318316Swollman 6418316Swollman#ifndef sgi 6518316Swollman#define _HAVE_SIN_LEN 6618316Swollman#endif 6718316Swollman 6819880Swollman#define MD5_DIGEST_LEN 16 6919880Swollmantypedef struct { 7019880Swollman u_int32_t state[4]; /* state (ABCD) */ 7119880Swollman u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ 7219880Swollman unsigned char buffer[64]; /* input buffer */ 7319880Swollman} MD5_CTX; 7419880Swollmanextern void MD5Init(MD5_CTX*); 7519880Swollmanextern void MD5Update(MD5_CTX*, u_char*, u_int); 7619880Swollmanextern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); 7719880Swollman 7819880Swollman 7918316Swollman#define WTIME 15 /* Time to wait for all responses */ 8018316Swollman#define STIME (250*1000) /* usec to wait for another response */ 8118316Swollman 8218316Swollmanint s; 8318316Swollman 8418316Swollmanchar *pgmname; 8518316Swollman 8618316Swollmanunion { 8718316Swollman struct rip rip; 8818316Swollman char packet[MAXPACKETSIZE+MAXPATHLEN]; 8918316Swollman} omsg_buf; 9018316Swollman#define OMSG omsg_buf.rip 9118316Swollmanint omsg_len = sizeof(struct rip); 9218316Swollman 9318316Swollmanunion { 9418316Swollman struct rip rip; 9518316Swollman char packet[MAXPACKETSIZE+1024]; 9618316Swollman } imsg_buf; 9718316Swollman#define IMSG imsg_buf.rip 9818316Swollman 9918316Swollmanint nflag; /* numbers, no names */ 10018316Swollmanint pflag; /* play the `gated` game */ 10118316Swollmanint ripv2 = 1; /* use RIP version 2 */ 10218316Swollmanint wtime = WTIME; 10318316Swollmanint rflag; /* 1=ask about a particular route */ 10419880Swollmanint trace, not_trace; /* send trace command or not */ 10519880Swollmanint auth_type = RIP_AUTH_NONE; 10619880Swollmanchar passwd[RIP_AUTH_PW_LEN]; 10719880Swollmanu_long keyid; 10818316Swollman 10918316Swollmanstruct timeval sent; /* when query sent */ 11018316Swollman 11118316Swollmanstatic void rip_input(struct sockaddr_in*, int); 11218316Swollmanstatic int out(char *); 11318316Swollmanstatic void trace_loop(char *argv[]); 11418316Swollmanstatic void query_loop(char *argv[], int); 11518316Swollmanstatic int getnet(char *, struct netinfo *); 11618316Swollmanstatic u_int std_mask(u_int); 11719880Swollmanstatic int parse_quote(char **, char *, char *, char *, int); 11818316Swollman 11918316Swollman 12018316Swollmanint 12118316Swollmanmain(int argc, 12218316Swollman char *argv[]) 12318316Swollman{ 12418316Swollman int ch, bsize; 12519880Swollman char *p, *options, *value, delim; 12618316Swollman 12718316Swollman OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 12818316Swollman OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 12918316Swollman OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 13018316Swollman 13118316Swollman pgmname = argv[0]; 13219880Swollman while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != EOF) 13318316Swollman switch (ch) { 13418316Swollman case 'n': 13518316Swollman not_trace = 1; 13618316Swollman nflag = 1; 13718316Swollman break; 13818316Swollman 13918316Swollman case 'p': 14018316Swollman not_trace = 1; 14118316Swollman pflag = 1; 14218316Swollman break; 14318316Swollman 14418316Swollman case '1': 14518316Swollman ripv2 = 0; 14618316Swollman break; 14718316Swollman 14818316Swollman case 'w': 14918316Swollman not_trace = 1; 15018316Swollman wtime = (int)strtoul(optarg, &p, 0); 15118316Swollman if (*p != '\0' 15218316Swollman || wtime <= 0) 15318316Swollman goto usage; 15418316Swollman break; 15518316Swollman 15618316Swollman case 'r': 15718316Swollman not_trace = 1; 15818316Swollman if (rflag) 15918316Swollman goto usage; 16018316Swollman rflag = getnet(optarg, &OMSG.rip_nets[0]); 16118316Swollman if (!rflag) { 16218316Swollman struct hostent *hp = gethostbyname(optarg); 16318316Swollman if (hp == 0) { 16418316Swollman fprintf(stderr, "%s: %s:", 16518316Swollman pgmname, optarg); 16618316Swollman herror(0); 16718316Swollman exit(1); 16818316Swollman } 16918316Swollman bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst, 17018316Swollman sizeof(OMSG.rip_nets[0].n_dst)); 17118316Swollman OMSG.rip_nets[0].n_family = RIP_AF_INET; 17218316Swollman OMSG.rip_nets[0].n_mask = -1; 17318316Swollman rflag = 1; 17418316Swollman } 17518316Swollman break; 17618316Swollman 17718316Swollman case 't': 17818316Swollman trace = 1; 17918316Swollman options = optarg; 18018316Swollman while (*options != '\0') { 18118316Swollman char *traceopts[] = { 18218316Swollman# define TRACE_ON 0 18318316Swollman "on", 18418316Swollman# define TRACE_MORE 1 18518316Swollman "more", 18618316Swollman# define TRACE_OFF 2 18718316Swollman "off", 18818316Swollman# define TRACE_DUMP 3 18918316Swollman "dump", 19018316Swollman 0 19118316Swollman }; 19218316Swollman switch (getsubopt(&options,traceopts,&value)) { 19318316Swollman case TRACE_ON: 19418316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 19518316Swollman if (!value 19618316Swollman || strlen(value) > MAXPATHLEN) 19718316Swollman goto usage; 19818316Swollman break; 19918316Swollman case TRACE_MORE: 20018316Swollman if (value) 20118316Swollman goto usage; 20218316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 20318316Swollman value = ""; 20418316Swollman break; 20518316Swollman case TRACE_OFF: 20618316Swollman if (value) 20718316Swollman goto usage; 20818316Swollman OMSG.rip_cmd = RIPCMD_TRACEOFF; 20918316Swollman value = ""; 21018316Swollman break; 21118316Swollman case TRACE_DUMP: 21218316Swollman if (value) 21318316Swollman goto usage; 21418316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 21518316Swollman value = "dump/../table"; 21618316Swollman break; 21718316Swollman default: 21818316Swollman goto usage; 21918316Swollman } 22018316Swollman strcpy((char*)OMSG.rip_tracefile, value); 22118316Swollman omsg_len += strlen(value) - sizeof(OMSG.ripun); 22218316Swollman } 22318316Swollman break; 22418316Swollman 22519880Swollman case 'a': 22619880Swollman not_trace = 1; 22719880Swollman p = strchr(optarg,'='); 22819880Swollman if (!p) 22919880Swollman goto usage; 23019880Swollman *p++ = '\0'; 23119880Swollman if (!strcasecmp("passwd",optarg)) 23219880Swollman auth_type = RIP_AUTH_PW; 23319880Swollman else if (!strcasecmp("md5_passwd",optarg)) 23419880Swollman auth_type = RIP_AUTH_MD5; 23519880Swollman else 23619880Swollman goto usage; 23719880Swollman if (0 > parse_quote(&p,"|",&delim, 23819880Swollman passwd,sizeof(passwd))) 23919880Swollman goto usage; 24019880Swollman if (auth_type == RIP_AUTH_MD5 24119880Swollman && delim == '|') { 24219880Swollman keyid = strtoul(p+1,&p,0); 24319880Swollman if (keyid > 255 || *p != '\0') 24419880Swollman goto usage; 24519880Swollman } else if (delim != '\0') { 24619880Swollman goto usage; 24719880Swollman } 24819880Swollman break; 24919880Swollman 25018316Swollman default: 25118316Swollman goto usage; 25218316Swollman } 25318316Swollman argv += optind; 25418316Swollman argc -= optind; 25518316Swollman if ((not_trace && trace) || argc == 0) { 25618316Swollmanusage: fprintf(stderr, "%s: [-np1v] [-r tgt_rt] [-w wtime]" 25719880Swollman " [-a type=passwd] host1 [host2 ...]\n" 25819880Swollman "or\t-t {on=filename|more|off|on=dump/../table}" 25919880Swollman " host1 [host2 ...]\n", 26018316Swollman pgmname); 26118316Swollman exit(1); 26218316Swollman } 26318316Swollman 26418316Swollman s = socket(AF_INET, SOCK_DGRAM, 0); 26518316Swollman if (s < 0) { 26618316Swollman perror("socket"); 26718316Swollman exit(2); 26818316Swollman } 26918316Swollman 27018316Swollman /* be prepared to receive a lot of routes */ 27118316Swollman for (bsize = 127*1024; ; bsize -= 1024) { 27218316Swollman if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 27318316Swollman &bsize, sizeof(bsize)) == 0) 27418316Swollman break; 27518316Swollman if (bsize <= 4*1024) { 27618316Swollman perror("setsockopt SO_RCVBUF"); 27718316Swollman break; 27818316Swollman } 27918316Swollman } 28018316Swollman 28118316Swollman if (trace) 28218316Swollman trace_loop(argv); 28318316Swollman else 28418316Swollman query_loop(argv, argc); 28518316Swollman /* NOTREACHED */ 28618316Swollman} 28718316Swollman 28818316Swollman 28918316Swollman/* tell the target hosts about tracing 29018316Swollman */ 29118316Swollmanstatic void 29218316Swollmantrace_loop(char *argv[]) 29318316Swollman{ 29418316Swollman struct sockaddr_in myaddr; 29518316Swollman int res; 29618316Swollman 29718316Swollman if (geteuid() != 0) { 29818316Swollman (void)fprintf(stderr, "-t requires UID 0\n"); 29918316Swollman exit(1); 30018316Swollman } 30118316Swollman 30218316Swollman if (ripv2) { 30318316Swollman OMSG.rip_vers = RIPv2; 30418316Swollman } else { 30518316Swollman OMSG.rip_vers = RIPv1; 30618316Swollman } 30718316Swollman 30818316Swollman bzero(&myaddr, sizeof(myaddr)); 30918316Swollman myaddr.sin_family = AF_INET; 31018316Swollman#ifdef _HAVE_SIN_LEN 31118316Swollman myaddr.sin_len = sizeof(myaddr); 31218316Swollman#endif 31318316Swollman myaddr.sin_port = htons(IPPORT_RESERVED-1); 31418316Swollman while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 31518316Swollman if (errno != EADDRINUSE 31618316Swollman || myaddr.sin_port == 0) { 31718316Swollman perror("bind"); 31818316Swollman exit(2); 31918316Swollman } 32018316Swollman myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 32118316Swollman } 32218316Swollman 32318316Swollman res = 1; 32418316Swollman while (*argv != 0) { 32518316Swollman if (out(*argv++) <= 0) 32618316Swollman res = 0; 32718316Swollman } 32818316Swollman exit(res); 32918316Swollman} 33018316Swollman 33118316Swollman 33218316Swollman/* query all of the listed hosts 33318316Swollman */ 33418316Swollmanstatic void 33518316Swollmanquery_loop(char *argv[], int argc) 33618316Swollman{ 33719880Swollman# define NA0 (OMSG.rip_auths[0]) 33819880Swollman# define NA2 (OMSG.rip_auths[2]) 33918316Swollman struct seen { 34018316Swollman struct seen *next; 34118316Swollman struct in_addr addr; 34218316Swollman } *seen, *sp; 34318316Swollman int answered = 0; 34418316Swollman int cc; 34518316Swollman fd_set bits; 34618316Swollman struct timeval now, delay; 34718316Swollman struct sockaddr_in from; 34818316Swollman int fromlen; 34919880Swollman MD5_CTX md5_ctx; 35018316Swollman 35118316Swollman 35218316Swollman OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 35318316Swollman if (ripv2) { 35418316Swollman OMSG.rip_vers = RIPv2; 35519880Swollman if (auth_type == RIP_AUTH_PW) { 35619880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 35719880Swollman NA0.a_family = RIP_AF_AUTH; 35819880Swollman NA0.a_type = RIP_AUTH_PW; 35919880Swollman bcopy(passwd, NA0.au.au_pw, 36019880Swollman RIP_AUTH_PW_LEN); 36119880Swollman omsg_len += sizeof(OMSG.rip_nets[0]); 36219880Swollman 36319880Swollman } else if (auth_type == RIP_AUTH_MD5) { 36419880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 36519880Swollman NA0.a_family = RIP_AF_AUTH; 36619880Swollman NA0.a_type = RIP_AUTH_MD5; 36719880Swollman NA0.au.a_md5.md5_keyid = (int8_t)keyid; 36819880Swollman NA0.au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN; 36919880Swollman NA0.au.a_md5.md5_seqno = 0; 37019880Swollman NA0.au.a_md5.md5_pkt_len = sizeof(OMSG.rip_nets[1]); 37119880Swollman NA2.a_family = RIP_AF_AUTH; 37219880Swollman NA2.a_type = 1; 37319880Swollman bcopy(passwd, NA2.au.au_pw, sizeof(NA2.au.au_pw)); 37419880Swollman MD5Init(&md5_ctx); 37519880Swollman MD5Update(&md5_ctx, (u_char *)&NA0, 37619880Swollman (char *)(&NA2+1) - (char *)&NA0); 37719880Swollman MD5Final(NA2.au.au_pw, &md5_ctx); 37819880Swollman omsg_len += 2*sizeof(OMSG.rip_nets[0]); 37919880Swollman } 38019880Swollman 38118316Swollman } else { 38218316Swollman OMSG.rip_vers = RIPv1; 38318316Swollman OMSG.rip_nets[0].n_mask = 0; 38418316Swollman } 38518316Swollman 38618316Swollman /* ask the first (valid) host */ 38718316Swollman seen = 0; 38818316Swollman while (0 > out(*argv++)) { 38918316Swollman if (*argv == 0) 39018316Swollman exit(-1); 39118316Swollman answered++; 39218316Swollman } 39318316Swollman 39418316Swollman FD_ZERO(&bits); 39518316Swollman for (;;) { 39618316Swollman FD_SET(s, &bits); 39718316Swollman delay.tv_sec = 0; 39818316Swollman delay.tv_usec = STIME; 39918316Swollman cc = select(s+1, &bits, 0,0, &delay); 40018316Swollman if (cc > 0) { 40118316Swollman fromlen = sizeof(from); 40218316Swollman cc = recvfrom(s, imsg_buf.packet, 40318316Swollman sizeof(imsg_buf.packet), 0, 40418316Swollman (struct sockaddr *)&from, &fromlen); 40518316Swollman if (cc < 0) { 40618316Swollman perror("recvfrom"); 40718316Swollman exit(1); 40818316Swollman } 40918316Swollman /* count the distinct responding hosts. 41018316Swollman * You cannot match responding hosts with 41118316Swollman * addresses to which queries were transmitted, 41218316Swollman * because a router might respond with a 41318316Swollman * different source address. 41418316Swollman */ 41518316Swollman for (sp = seen; sp != 0; sp = sp->next) { 41618316Swollman if (sp->addr.s_addr == from.sin_addr.s_addr) 41718316Swollman break; 41818316Swollman } 41918316Swollman if (sp == 0) { 42018316Swollman sp = malloc(sizeof(*sp)); 42118316Swollman sp->addr = from.sin_addr; 42218316Swollman sp->next = seen; 42318316Swollman seen = sp; 42418316Swollman answered++; 42518316Swollman } 42618316Swollman 42718316Swollman rip_input(&from, cc); 42818316Swollman continue; 42918316Swollman } 43018316Swollman 43118316Swollman if (cc < 0) { 43218316Swollman if ( errno == EINTR) 43318316Swollman continue; 43418316Swollman perror("select"); 43518316Swollman exit(1); 43618316Swollman } 43718316Swollman 43818316Swollman /* After a pause in responses, probe another host. 43918316Swollman * This reduces the intermingling of answers. 44018316Swollman */ 44118316Swollman while (*argv != 0 && 0 > out(*argv++)) 44218316Swollman answered++; 44318316Swollman 44418316Swollman /* continue until no more packets arrive 44518316Swollman * or we have heard from all hosts 44618316Swollman */ 44718316Swollman if (answered >= argc) 44818316Swollman break; 44918316Swollman 45018316Swollman /* or until we have waited a long time 45118316Swollman */ 45218316Swollman if (gettimeofday(&now, 0) < 0) { 45318316Swollman perror("gettimeofday(now)"); 45418316Swollman exit(1); 45518316Swollman } 45618316Swollman if (sent.tv_sec + wtime <= now.tv_sec) 45718316Swollman break; 45818316Swollman } 45918316Swollman 46018316Swollman /* fail if there was no answer */ 46118316Swollman exit (answered >= argc ? 0 : 1); 46218316Swollman} 46318316Swollman 46418316Swollman 46519880Swollman/* send to one host 46618316Swollman */ 46718316Swollmanstatic int 46818316Swollmanout(char *host) 46918316Swollman{ 47018316Swollman struct sockaddr_in router; 47118316Swollman struct hostent *hp; 47218316Swollman 47318316Swollman if (gettimeofday(&sent, 0) < 0) { 47418316Swollman perror("gettimeofday(sent)"); 47518316Swollman return -1; 47618316Swollman } 47718316Swollman 47818316Swollman bzero(&router, sizeof(router)); 47918316Swollman router.sin_family = AF_INET; 48018316Swollman#ifdef _HAVE_SIN_LEN 48118316Swollman router.sin_len = sizeof(router); 48218316Swollman#endif 48318316Swollman if (!inet_aton(host, &router.sin_addr)) { 48418316Swollman hp = gethostbyname(host); 48518316Swollman if (hp == 0) { 48618316Swollman herror(host); 48718316Swollman return -1; 48818316Swollman } 48918316Swollman bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr)); 49018316Swollman } 49118316Swollman router.sin_port = htons(RIP_PORT); 49218316Swollman 49318316Swollman if (sendto(s, &omsg_buf, omsg_len, 0, 49418316Swollman (struct sockaddr *)&router, sizeof(router)) < 0) { 49518316Swollman perror(host); 49618316Swollman return -1; 49718316Swollman } 49818316Swollman 49918316Swollman return 0; 50018316Swollman} 50118316Swollman 50218316Swollman 50318316Swollman/* 50419880Swollman * Convert string to printable characters 50519880Swollman */ 50619880Swollmanstatic char * 50719880Swollmanqstring(u_char *s, int len) 50819880Swollman{ 50919880Swollman static char buf[8*20+1]; 51019880Swollman char *p; 51119880Swollman u_char *s2, c; 51219880Swollman 51319880Swollman 51419880Swollman for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 51519880Swollman c = *s++; 51619880Swollman if (c == '\0') { 51719880Swollman for (s2 = s+1; s2 < &s[len]; s2++) { 51819880Swollman if (*s2 != '\0') 51919880Swollman break; 52019880Swollman } 52119880Swollman if (s2 >= &s[len]) 52219880Swollman goto exit; 52319880Swollman } 52419880Swollman 52519880Swollman if (c >= ' ' && c < 0x7f && c != '\\') { 52619880Swollman *p++ = c; 52719880Swollman continue; 52819880Swollman } 52919880Swollman *p++ = '\\'; 53019880Swollman switch (c) { 53119880Swollman case '\\': 53219880Swollman *p++ = '\\'; 53319880Swollman break; 53419880Swollman case '\n': 53519880Swollman *p++= 'n'; 53619880Swollman break; 53719880Swollman case '\r': 53819880Swollman *p++= 'r'; 53919880Swollman break; 54019880Swollman case '\t': 54119880Swollman *p++ = 't'; 54219880Swollman break; 54319880Swollman case '\b': 54419880Swollman *p++ = 'b'; 54519880Swollman break; 54619880Swollman default: 54719880Swollman p += sprintf(p,"%o",c); 54819880Swollman break; 54919880Swollman } 55019880Swollman } 55119880Swollmanexit: 55219880Swollman *p = '\0'; 55319880Swollman return buf; 55419880Swollman} 55519880Swollman 55619880Swollman 55719880Swollman/* 55818316Swollman * Handle an incoming RIP packet. 55918316Swollman */ 56018316Swollmanstatic void 56118316Swollmanrip_input(struct sockaddr_in *from, 56218316Swollman int size) 56318316Swollman{ 56418316Swollman struct netinfo *n, *lim; 56518316Swollman struct in_addr in; 56618316Swollman char *name; 56718316Swollman char net_buf[80]; 56818316Swollman u_int mask, dmask; 56918316Swollman char *sp; 57018316Swollman int i; 57118316Swollman struct hostent *hp; 57218316Swollman struct netent *np; 57319880Swollman struct netauth *na; 57418316Swollman 57518316Swollman 57618316Swollman if (nflag) { 57718316Swollman printf("%s:", inet_ntoa(from->sin_addr)); 57818316Swollman } else { 57918316Swollman hp = gethostbyaddr((char*)&from->sin_addr, 58018316Swollman sizeof(struct in_addr), AF_INET); 58118316Swollman if (hp == 0) { 58218316Swollman printf("%s:", 58318316Swollman inet_ntoa(from->sin_addr)); 58418316Swollman } else { 58518316Swollman printf("%s (%s):", hp->h_name, 58618316Swollman inet_ntoa(from->sin_addr)); 58718316Swollman } 58818316Swollman } 58918316Swollman if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 59018316Swollman printf("\n unexpected response type %d\n", IMSG.rip_cmd); 59118316Swollman return; 59218316Swollman } 59318316Swollman printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 59418316Swollman (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 59518316Swollman size); 59618316Swollman if (size > MAXPACKETSIZE) { 59718316Swollman if (size > sizeof(imsg_buf) - sizeof(*n)) { 59818316Swollman printf(" at least %d bytes too long\n", 59918316Swollman size-MAXPACKETSIZE); 60018316Swollman size = sizeof(imsg_buf) - sizeof(*n); 60118316Swollman } else { 60218316Swollman printf(" %d bytes too long\n", 60318316Swollman size-MAXPACKETSIZE); 60418316Swollman } 60518316Swollman } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 60618316Swollman printf(" response of bad length=%d\n", size); 60718316Swollman } 60818316Swollman 60918316Swollman n = IMSG.rip_nets; 61018316Swollman lim = (struct netinfo *)((char*)n + size) - 1; 61118316Swollman for (; n <= lim; n++) { 61218316Swollman name = ""; 61318316Swollman if (n->n_family == RIP_AF_INET) { 61418316Swollman in.s_addr = n->n_dst; 61518316Swollman (void)strcpy(net_buf, inet_ntoa(in)); 61618316Swollman 61718316Swollman mask = ntohl(n->n_mask); 61818316Swollman dmask = mask & -mask; 61918316Swollman if (mask != 0) { 62018316Swollman sp = &net_buf[strlen(net_buf)]; 62118316Swollman if (IMSG.rip_vers == RIPv1) { 62218316Swollman (void)sprintf(sp," mask=%#x ? ",mask); 62318316Swollman mask = 0; 62418316Swollman } else if (mask + dmask == 0) { 62518316Swollman for (i = 0; 62618316Swollman (i != 32 62718316Swollman && ((1<<i)&mask) == 0); 62818316Swollman i++) 62918316Swollman continue; 63018316Swollman (void)sprintf(sp, "/%d",32-i); 63118316Swollman } else { 63218316Swollman (void)sprintf(sp," (mask %#x)", mask); 63318316Swollman } 63418316Swollman } 63518316Swollman 63618316Swollman if (!nflag) { 63718316Swollman if (mask == 0) { 63818316Swollman mask = std_mask(in.s_addr); 63918316Swollman if ((ntohl(in.s_addr) & ~mask) != 0) 64018316Swollman mask = 0; 64118316Swollman } 64218316Swollman /* Without a netmask, do not worry about 64318316Swollman * whether the destination is a host or a 64418316Swollman * network. Try both and use the first name 64518316Swollman * we get. 64618316Swollman * 64718316Swollman * If we have a netmask we can make a 64818316Swollman * good guess. 64918316Swollman */ 65018316Swollman if ((in.s_addr & ~mask) == 0) { 65118316Swollman np = getnetbyaddr((long)in.s_addr, 65218316Swollman AF_INET); 65318316Swollman if (np != 0) 65418316Swollman name = np->n_name; 65518316Swollman else if (in.s_addr == 0) 65618316Swollman name = "default"; 65718316Swollman } 65818316Swollman if (name[0] == '\0' 65918316Swollman && ((in.s_addr & ~mask) != 0 66018316Swollman || mask == 0xffffffff)) { 66118316Swollman hp = gethostbyaddr((char*)&in, 66218316Swollman sizeof(in), 66318316Swollman AF_INET); 66418316Swollman if (hp != 0) 66518316Swollman name = hp->h_name; 66618316Swollman } 66718316Swollman } 66818316Swollman 66918316Swollman } else if (n->n_family == RIP_AF_AUTH) { 67019880Swollman na = (struct netauth*)n; 67119880Swollman if (na->a_type == RIP_AUTH_PW 67219880Swollman && n == IMSG.rip_nets) { 67319880Swollman (void)printf(" Password Authentication:" 67419880Swollman " \"%s\"\n", 67519880Swollman qstring(na->au.au_pw, 67619880Swollman RIP_AUTH_PW_LEN)); 67719880Swollman continue; 67819880Swollman } 67919880Swollman 68019880Swollman if (na->a_type == RIP_AUTH_MD5 68119880Swollman && n == IMSG.rip_nets) { 68219880Swollman (void)printf(" MD5 Authentication" 68319880Swollman " len=%d KeyID=%d" 68419880Swollman " seqno=%d" 68519880Swollman " rsvd=%#x,%#x\n", 68619880Swollman na->au.a_md5.md5_pkt_len, 68719880Swollman na->au.a_md5.md5_keyid, 68819880Swollman na->au.a_md5.md5_seqno, 68919880Swollman na->au.a_md5.rsvd[0], 69019880Swollman na->au.a_md5.rsvd[1]); 69119880Swollman continue; 69219880Swollman } 69319880Swollman (void)printf(" Authentication type %d: ", 69419880Swollman ntohs(na->a_type)); 69519880Swollman for (i = 0; i < sizeof(na->au.au_pw); i++) 69619880Swollman (void)printf("%02x ", na->au.au_pw[i]); 69718316Swollman putc('\n', stdout); 69818316Swollman continue; 69918316Swollman 70018316Swollman } else { 70118316Swollman (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 70218316Swollman ntohs(n->n_family), 70318316Swollman (char)(n->n_dst >> 24), 70418316Swollman (char)(n->n_dst >> 16), 70518316Swollman (char)(n->n_dst >> 8), 70618316Swollman (char)n->n_dst); 70718316Swollman } 70818316Swollman 70918316Swollman (void)printf(" %-18s metric %2d %-10s", 71018316Swollman net_buf, ntohl(n->n_metric), name); 71118316Swollman 71218316Swollman if (n->n_nhop != 0) { 71318316Swollman in.s_addr = n->n_nhop; 71418316Swollman if (nflag) 71518316Swollman hp = 0; 71618316Swollman else 71718316Swollman hp = gethostbyaddr((char*)&in, sizeof(in), 71818316Swollman AF_INET); 71918316Swollman (void)printf(" nhop=%-15s%s", 72018316Swollman (hp != 0) ? hp->h_name : inet_ntoa(in), 72118316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 72218316Swollman } 72318316Swollman if (n->n_tag != 0) 72418316Swollman (void)printf(" tag=%#x%s", n->n_tag, 72518316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 72618316Swollman putc('\n', stdout); 72718316Swollman } 72818316Swollman} 72918316Swollman 73018316Swollman 73118316Swollman/* Return the classical netmask for an IP address. 73218316Swollman */ 73318316Swollmanstatic u_int 73418316Swollmanstd_mask(u_int addr) /* in network order */ 73518316Swollman{ 73618316Swollman NTOHL(addr); /* was a host, not a network */ 73718316Swollman 73818316Swollman if (addr == 0) /* default route has mask 0 */ 73918316Swollman return 0; 74018316Swollman if (IN_CLASSA(addr)) 74118316Swollman return IN_CLASSA_NET; 74218316Swollman if (IN_CLASSB(addr)) 74318316Swollman return IN_CLASSB_NET; 74418316Swollman return IN_CLASSC_NET; 74518316Swollman} 74618316Swollman 74718316Swollman 74818316Swollman/* get a network number as a name or a number, with an optional "/xx" 74918316Swollman * netmask. 75018316Swollman */ 75118316Swollmanstatic int /* 0=bad */ 75218316Swollmangetnet(char *name, 75318316Swollman struct netinfo *rt) 75418316Swollman{ 75518316Swollman int i; 75618316Swollman struct netent *nentp; 75718316Swollman u_int mask; 75818316Swollman struct in_addr in; 75918316Swollman char hname[MAXHOSTNAMELEN+1]; 76018316Swollman char *mname, *p; 76118316Swollman 76218316Swollman 76318316Swollman /* Detect and separate "1.2.3.4/24" 76418316Swollman */ 76518316Swollman if (0 != (mname = rindex(name,'/'))) { 76618316Swollman i = (int)(mname - name); 76718316Swollman if (i > sizeof(hname)-1) /* name too long */ 76818316Swollman return 0; 76918316Swollman bcopy(name, hname, i); 77018316Swollman hname[i] = '\0'; 77118316Swollman mname++; 77218316Swollman name = hname; 77318316Swollman } 77418316Swollman 77518316Swollman nentp = getnetbyname(name); 77618316Swollman if (nentp != 0) { 77718316Swollman in.s_addr = nentp->n_net; 77818316Swollman } else if (inet_aton(name, &in) == 1) { 77918316Swollman NTOHL(in.s_addr); 78018316Swollman } else { 78118316Swollman return 0; 78218316Swollman } 78318316Swollman 78418316Swollman if (mname == 0) { 78518316Swollman mask = std_mask(in.s_addr); 78618316Swollman if ((~mask & in.s_addr) != 0) 78718316Swollman mask = 0xffffffff; 78818316Swollman } else { 78918316Swollman mask = (u_int)strtoul(mname, &p, 0); 79018316Swollman if (*p != '\0' || mask > 32) 79118316Swollman return 0; 79218316Swollman mask = 0xffffffff << (32-mask); 79318316Swollman } 79418316Swollman 79518316Swollman rt->n_dst = htonl(in.s_addr); 79618316Swollman rt->n_family = RIP_AF_INET; 79718316Swollman rt->n_mask = htonl(mask); 79818316Swollman return 1; 79918316Swollman} 80019880Swollman 80119880Swollman 80219880Swollman/* strtok(), but honoring backslash 80319880Swollman */ 80419880Swollmanstatic int /* -1=bad */ 80519880Swollmanparse_quote(char **linep, 80619880Swollman char *delims, 80719880Swollman char *delimp, 80819880Swollman char *buf, 80919880Swollman int lim) 81019880Swollman{ 81119880Swollman char c, *pc, *p; 81219880Swollman 81319880Swollman 81419880Swollman pc = *linep; 81519880Swollman if (*pc == '\0') 81619880Swollman return -1; 81719880Swollman 81819880Swollman for (;;) { 81919880Swollman if (lim == 0) 82019880Swollman return -1; 82119880Swollman c = *pc++; 82219880Swollman if (c == '\0') 82319880Swollman break; 82419880Swollman 82519880Swollman if (c == '\\' && pc != '\0') { 82619880Swollman if ((c = *pc++) == 'n') { 82719880Swollman c = '\n'; 82819880Swollman } else if (c == 'r') { 82919880Swollman c = '\r'; 83019880Swollman } else if (c == 't') { 83119880Swollman c = '\t'; 83219880Swollman } else if (c == 'b') { 83319880Swollman c = '\b'; 83419880Swollman } else if (c >= '0' && c <= '7') { 83519880Swollman c -= '0'; 83619880Swollman if (*pc >= '0' && *pc <= '7') { 83719880Swollman c = (c<<3)+(*pc++ - '0'); 83819880Swollman if (*pc >= '0' && *pc <= '7') 83919880Swollman c = (c<<3)+(*pc++ - '0'); 84019880Swollman } 84119880Swollman } 84219880Swollman 84319880Swollman } else { 84419880Swollman for (p = delims; *p != '\0'; ++p) { 84519880Swollman if (*p == c) 84619880Swollman goto exit; 84719880Swollman } 84819880Swollman } 84919880Swollman 85019880Swollman *buf++ = c; 85119880Swollman --lim; 85219880Swollman } 85319880Swollmanexit: 85419880Swollman if (delimp != 0) 85519880Swollman *delimp = c; 85619880Swollman *linep = pc-1; 85719880Swollman if (lim != 0) 85819880Swollman *buf = '\0'; 85919880Swollman return 0; 86019880Swollman} 861