rtquery.c revision 46303
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 1446303Smarkm * must display the following acknowledgment: 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. 3246303Smarkm * 3346303Smarkm * $Id$ 3418316Swollman */ 3518316Swollman 3646303Smarkmchar copyright[] = 3718316Swollman"@(#) Copyright (c) 1982, 1986, 1993\n\ 3818316Swollman The Regents of the University of California. All rights reserved.\n"; 3918316Swollman 4046303Smarkm#include <sys/cdefs.h> 4118316Swollman#include <sys/param.h> 4246303Smarkm#include <sys/protosw.h> 4318316Swollman#include <sys/socket.h> 4418316Swollman#include <sys/time.h> 4518316Swollman#include <netinet/in.h> 4618316Swollman#define RIPVERSION RIPv2 4718316Swollman#include <protocols/routed.h> 4818316Swollman#include <arpa/inet.h> 4946303Smarkm#include <netdb.h> 5032502Scharnier#include <errno.h> 5146303Smarkm#include <unistd.h> 5218316Swollman#include <stdio.h> 5318316Swollman#include <stdlib.h> 5418316Swollman#include <string.h> 5518316Swollman#ifdef sgi 5618316Swollman#include <strings.h> 5718316Swollman#include <bstring.h> 5818316Swollman#endif 5918316Swollman 6046303Smarkm#if !defined(sgi) && !defined(__NetBSD__) 6146303Smarkmstatic char sccsid[] __attribute__((unused))= "@(#)query.c 8.1 (Berkeley) 6/5/93"; 6246303Smarkm#elif defined(__NetBSD__) 6346303Smarkm__RCSID("$NetBSD: rtquery.c,v 1.10 1999/02/23 10:47:41 christos Exp $"); 6446303Smarkm#endif 6546303Smarkm#ident "$Revision: 2.17 $" 6646303Smarkm 6718316Swollman#ifndef sgi 6818316Swollman#define _HAVE_SIN_LEN 6918316Swollman#endif 7018316Swollman 7146303Smarkm#define MD5_DIGEST_LEN 16 7246303Smarkmtypedef struct { 7346303Smarkm u_int32_t state[4]; /* state (ABCD) */ 7446303Smarkm u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ 7546303Smarkm unsigned char buffer[64]; /* input buffer */ 7646303Smarkm} MD5_CTX; 7746303Smarkmextern void MD5Init(MD5_CTX*); 7846303Smarkmextern void MD5Update(MD5_CTX*, u_char*, u_int); 7946303Smarkmextern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); 8046303Smarkm 8146303Smarkm 8218316Swollman#define WTIME 15 /* Time to wait for all responses */ 8318316Swollman#define STIME (250*1000) /* usec to wait for another response */ 8418316Swollman 8546303Smarkmint soc; 8618316Swollman 8746303Smarkmconst char *pgmname; 8846303Smarkm 8918316Swollmanunion { 9018316Swollman struct rip rip; 9118316Swollman char packet[MAXPACKETSIZE+MAXPATHLEN]; 9218316Swollman} omsg_buf; 9318316Swollman#define OMSG omsg_buf.rip 9418316Swollmanint omsg_len = sizeof(struct rip); 9518316Swollman 9618316Swollmanunion { 9718316Swollman struct rip rip; 9818316Swollman char packet[MAXPACKETSIZE+1024]; 9918316Swollman } imsg_buf; 10018316Swollman#define IMSG imsg_buf.rip 10118316Swollman 10218316Swollmanint nflag; /* numbers, no names */ 10318316Swollmanint pflag; /* play the `gated` game */ 10418316Swollmanint ripv2 = 1; /* use RIP version 2 */ 10518316Swollmanint wtime = WTIME; 10618316Swollmanint rflag; /* 1=ask about a particular route */ 10719880Swollmanint trace, not_trace; /* send trace command or not */ 10819880Swollmanint auth_type = RIP_AUTH_NONE; 10919880Swollmanchar passwd[RIP_AUTH_PW_LEN]; 11019880Swollmanu_long keyid; 11118316Swollman 11218316Swollmanstruct timeval sent; /* when query sent */ 11318316Swollman 11446303Smarkmstatic char localhost_str[] = "localhost"; 11546303Smarkmstatic char *default_argv[] = {localhost_str, 0}; 11646303Smarkm 11718316Swollmanstatic void rip_input(struct sockaddr_in*, int); 11846303Smarkmstatic int out(const char *); 11946303Smarkmstatic void trace_loop(char *argv[]) __attribute((__noreturn__)); 12046303Smarkmstatic void query_loop(char *argv[], int) __attribute((__noreturn__)); 12118316Swollmanstatic int getnet(char *, struct netinfo *); 12218316Swollmanstatic u_int std_mask(u_int); 12346303Smarkmstatic int parse_quote(char **, const char *, char *, char *, int); 12437908Scharnierstatic void usage(void); 12518316Swollman 12646303Smarkm 12737908Scharnierint 12818316Swollmanmain(int argc, 12918316Swollman char *argv[]) 13018316Swollman{ 13118316Swollman int ch, bsize; 13219880Swollman char *p, *options, *value, delim; 13346303Smarkm const char *result; 13418316Swollman 13518316Swollman OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 13618316Swollman OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 13718316Swollman OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 13818316Swollman 13946303Smarkm pgmname = argv[0]; 14024359Simp while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) 14118316Swollman switch (ch) { 14218316Swollman case 'n': 14318316Swollman not_trace = 1; 14418316Swollman nflag = 1; 14518316Swollman break; 14618316Swollman 14718316Swollman case 'p': 14818316Swollman not_trace = 1; 14918316Swollman pflag = 1; 15018316Swollman break; 15118316Swollman 15218316Swollman case '1': 15318316Swollman ripv2 = 0; 15418316Swollman break; 15518316Swollman 15618316Swollman case 'w': 15718316Swollman not_trace = 1; 15818316Swollman wtime = (int)strtoul(optarg, &p, 0); 15918316Swollman if (*p != '\0' 16018316Swollman || wtime <= 0) 16137908Scharnier usage(); 16218316Swollman break; 16318316Swollman 16418316Swollman case 'r': 16518316Swollman not_trace = 1; 16618316Swollman if (rflag) 16737908Scharnier usage(); 16818316Swollman rflag = getnet(optarg, &OMSG.rip_nets[0]); 16918316Swollman if (!rflag) { 17018316Swollman struct hostent *hp = gethostbyname(optarg); 17146303Smarkm if (hp == 0) { 17246303Smarkm fprintf(stderr, "%s: %s:", 17346303Smarkm pgmname, optarg); 17446303Smarkm herror(0); 17546303Smarkm exit(1); 17646303Smarkm } 17746303Smarkm memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr, 17846303Smarkm sizeof(OMSG.rip_nets[0].n_dst)); 17918316Swollman OMSG.rip_nets[0].n_family = RIP_AF_INET; 18018316Swollman OMSG.rip_nets[0].n_mask = -1; 18118316Swollman rflag = 1; 18218316Swollman } 18318316Swollman break; 18418316Swollman 18518316Swollman case 't': 18618316Swollman trace = 1; 18718316Swollman options = optarg; 18818316Swollman while (*options != '\0') { 18946303Smarkm /* messy complications to make -W -Wall happy */ 19046303Smarkm static char on_str[] = "on"; 19146303Smarkm static char more_str[] = "more"; 19246303Smarkm static char off_str[] = "off"; 19346303Smarkm static char dump_str[] = "dump"; 19446303Smarkm static char *traceopts[] = { 19518316Swollman# define TRACE_ON 0 19646303Smarkm on_str, 19718316Swollman# define TRACE_MORE 1 19846303Smarkm more_str, 19918316Swollman# define TRACE_OFF 2 20046303Smarkm off_str, 20118316Swollman# define TRACE_DUMP 3 20246303Smarkm dump_str, 20318316Swollman 0 20418316Swollman }; 20546303Smarkm result = ""; 20618316Swollman switch (getsubopt(&options,traceopts,&value)) { 20718316Swollman case TRACE_ON: 20818316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 20918316Swollman if (!value 21018316Swollman || strlen(value) > MAXPATHLEN) 21146303Smarkm usage(); 21246303Smarkm result = value; 21318316Swollman break; 21418316Swollman case TRACE_MORE: 21518316Swollman if (value) 21646303Smarkm usage(); 21718316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 21818316Swollman break; 21918316Swollman case TRACE_OFF: 22018316Swollman if (value) 22146303Smarkm usage(); 22218316Swollman OMSG.rip_cmd = RIPCMD_TRACEOFF; 22318316Swollman break; 22418316Swollman case TRACE_DUMP: 22518316Swollman if (value) 22646303Smarkm usage(); 22718316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 22846303Smarkm result = "dump/../table"; 22918316Swollman break; 23018316Swollman default: 23137908Scharnier usage(); 23218316Swollman } 23346303Smarkm strcpy((char*)OMSG.rip_tracefile, result); 23446303Smarkm omsg_len += strlen(result) - sizeof(OMSG.ripun); 23518316Swollman } 23618316Swollman break; 23718316Swollman 23819880Swollman case 'a': 23919880Swollman not_trace = 1; 24019880Swollman p = strchr(optarg,'='); 24119880Swollman if (!p) 24237908Scharnier usage(); 24319880Swollman *p++ = '\0'; 24419880Swollman if (!strcasecmp("passwd",optarg)) 24519880Swollman auth_type = RIP_AUTH_PW; 24619880Swollman else if (!strcasecmp("md5_passwd",optarg)) 24719880Swollman auth_type = RIP_AUTH_MD5; 24819880Swollman else 24937908Scharnier usage(); 25019880Swollman if (0 > parse_quote(&p,"|",&delim, 25146303Smarkm passwd, sizeof(passwd))) 25237908Scharnier usage(); 25319880Swollman if (auth_type == RIP_AUTH_MD5 25419880Swollman && delim == '|') { 25519880Swollman keyid = strtoul(p+1,&p,0); 25619880Swollman if (keyid > 255 || *p != '\0') 25737908Scharnier usage(); 25819880Swollman } else if (delim != '\0') { 25937908Scharnier usage(); 26019880Swollman } 26119880Swollman break; 26219880Swollman 26318316Swollman default: 26437908Scharnier usage(); 26518316Swollman } 26618316Swollman argv += optind; 26718316Swollman argc -= optind; 26846303Smarkm if (not_trace && trace) 26937908Scharnier usage(); 27046303Smarkm if (argc == 0) { 27146303Smarkm argc = 1; 27246303Smarkm argv = default_argv; 27346303Smarkm } 27418316Swollman 27546303Smarkm soc = socket(AF_INET, SOCK_DGRAM, 0); 27646303Smarkm if (soc < 0) { 27746303Smarkm perror("socket"); 27846303Smarkm exit(2); 27946303Smarkm } 28018316Swollman 28118316Swollman /* be prepared to receive a lot of routes */ 28218316Swollman for (bsize = 127*1024; ; bsize -= 1024) { 28346303Smarkm if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF, 28418316Swollman &bsize, sizeof(bsize)) == 0) 28518316Swollman break; 28618316Swollman if (bsize <= 4*1024) { 28746303Smarkm perror("setsockopt SO_RCVBUF"); 28818316Swollman break; 28918316Swollman } 29018316Swollman } 29118316Swollman 29218316Swollman if (trace) 29318316Swollman trace_loop(argv); 29418316Swollman else 29518316Swollman query_loop(argv, argc); 29618316Swollman /* NOTREACHED */ 29746303Smarkm return 0; 29818316Swollman} 29918316Swollman 30046303Smarkm 30137908Scharnierstatic void 30246303Smarkmusage(void) 30337908Scharnier{ 30446303Smarkm fprintf(stderr, 30546303Smarkm "usage: rtquery [-np1] [-r tgt_rt] [-w wtime]" 30646303Smarkm " [-a type=passwd] host1 [host2 ...]\n" 30746303Smarkm "\trtquery -t {on=filename|more|off|dump}" 30846303Smarkm " host1 [host2 ...]\n"); 30937908Scharnier exit(1); 31037908Scharnier} 31118316Swollman 31246303Smarkm 31318316Swollman/* tell the target hosts about tracing 31418316Swollman */ 31518316Swollmanstatic void 31618316Swollmantrace_loop(char *argv[]) 31718316Swollman{ 31818316Swollman struct sockaddr_in myaddr; 31918316Swollman int res; 32018316Swollman 32146303Smarkm if (geteuid() != 0) { 32246303Smarkm (void)fprintf(stderr, "-t requires UID 0\n"); 32346303Smarkm exit(1); 32446303Smarkm } 32518316Swollman 32618316Swollman if (ripv2) { 32718316Swollman OMSG.rip_vers = RIPv2; 32818316Swollman } else { 32918316Swollman OMSG.rip_vers = RIPv1; 33018316Swollman } 33118316Swollman 33246303Smarkm memset(&myaddr, 0, sizeof(myaddr)); 33318316Swollman myaddr.sin_family = AF_INET; 33418316Swollman#ifdef _HAVE_SIN_LEN 33518316Swollman myaddr.sin_len = sizeof(myaddr); 33618316Swollman#endif 33718316Swollman myaddr.sin_port = htons(IPPORT_RESERVED-1); 33846303Smarkm while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 33946303Smarkm if (errno != EADDRINUSE 34046303Smarkm || myaddr.sin_port == 0) { 34146303Smarkm perror("bind"); 34246303Smarkm exit(2); 34346303Smarkm } 34418316Swollman myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 34518316Swollman } 34618316Swollman 34718316Swollman res = 1; 34818316Swollman while (*argv != 0) { 34918316Swollman if (out(*argv++) <= 0) 35018316Swollman res = 0; 35118316Swollman } 35218316Swollman exit(res); 35318316Swollman} 35418316Swollman 35518316Swollman 35618316Swollman/* query all of the listed hosts 35718316Swollman */ 35818316Swollmanstatic void 35918316Swollmanquery_loop(char *argv[], int argc) 36018316Swollman{ 36119880Swollman# define NA0 (OMSG.rip_auths[0]) 36219880Swollman# define NA2 (OMSG.rip_auths[2]) 36318316Swollman struct seen { 36418316Swollman struct seen *next; 36518316Swollman struct in_addr addr; 36618316Swollman } *seen, *sp; 36718316Swollman int answered = 0; 36818316Swollman int cc; 36918316Swollman fd_set bits; 37018316Swollman struct timeval now, delay; 37118316Swollman struct sockaddr_in from; 37218316Swollman int fromlen; 37319880Swollman MD5_CTX md5_ctx; 37418316Swollman 37518316Swollman 37618316Swollman OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 37718316Swollman if (ripv2) { 37818316Swollman OMSG.rip_vers = RIPv2; 37919880Swollman if (auth_type == RIP_AUTH_PW) { 38019880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 38119880Swollman NA0.a_family = RIP_AF_AUTH; 38219880Swollman NA0.a_type = RIP_AUTH_PW; 38346303Smarkm memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN); 38419880Swollman omsg_len += sizeof(OMSG.rip_nets[0]); 38519880Swollman 38619880Swollman } else if (auth_type == RIP_AUTH_MD5) { 38719880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 38819880Swollman NA0.a_family = RIP_AF_AUTH; 38919880Swollman NA0.a_type = RIP_AUTH_MD5; 39019880Swollman NA0.au.a_md5.md5_keyid = (int8_t)keyid; 39146303Smarkm NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; 39219880Swollman NA0.au.a_md5.md5_seqno = 0; 39346303Smarkm cc = (char *)&NA2-(char *)&OMSG; 39446303Smarkm NA0.au.a_md5.md5_pkt_len = htons(cc); 39519880Swollman NA2.a_family = RIP_AF_AUTH; 39646303Smarkm NA2.a_type = htons(1); 39719880Swollman MD5Init(&md5_ctx); 39846303Smarkm MD5Update(&md5_ctx, 39946303Smarkm (u_char *)&OMSG, cc); 40046303Smarkm MD5Update(&md5_ctx, 40146303Smarkm (u_char *)passwd, RIP_AUTH_MD5_LEN); 40219880Swollman MD5Final(NA2.au.au_pw, &md5_ctx); 40319880Swollman omsg_len += 2*sizeof(OMSG.rip_nets[0]); 40419880Swollman } 40519880Swollman 40618316Swollman } else { 40718316Swollman OMSG.rip_vers = RIPv1; 40818316Swollman OMSG.rip_nets[0].n_mask = 0; 40918316Swollman } 41018316Swollman 41118316Swollman /* ask the first (valid) host */ 41218316Swollman seen = 0; 41318316Swollman while (0 > out(*argv++)) { 41418316Swollman if (*argv == 0) 41546303Smarkm exit(-1); 41618316Swollman answered++; 41718316Swollman } 41818316Swollman 41918316Swollman FD_ZERO(&bits); 42018316Swollman for (;;) { 42146303Smarkm FD_SET(soc, &bits); 42218316Swollman delay.tv_sec = 0; 42318316Swollman delay.tv_usec = STIME; 42446303Smarkm cc = select(soc+1, &bits, 0,0, &delay); 42518316Swollman if (cc > 0) { 42618316Swollman fromlen = sizeof(from); 42746303Smarkm cc = recvfrom(soc, imsg_buf.packet, 42818316Swollman sizeof(imsg_buf.packet), 0, 42918316Swollman (struct sockaddr *)&from, &fromlen); 43046303Smarkm if (cc < 0) { 43146303Smarkm perror("recvfrom"); 43246303Smarkm exit(1); 43346303Smarkm } 43418316Swollman /* count the distinct responding hosts. 43518316Swollman * You cannot match responding hosts with 43618316Swollman * addresses to which queries were transmitted, 43718316Swollman * because a router might respond with a 43818316Swollman * different source address. 43918316Swollman */ 44018316Swollman for (sp = seen; sp != 0; sp = sp->next) { 44118316Swollman if (sp->addr.s_addr == from.sin_addr.s_addr) 44218316Swollman break; 44318316Swollman } 44418316Swollman if (sp == 0) { 44518316Swollman sp = malloc(sizeof(*sp)); 44646303Smarkm if (sp == 0) { 44746303Smarkm fprintf(stderr, 44846303Smarkm "rtquery: malloc failed\n"); 44946303Smarkm exit(1); 45046303Smarkm } 45118316Swollman sp->addr = from.sin_addr; 45218316Swollman sp->next = seen; 45318316Swollman seen = sp; 45418316Swollman answered++; 45518316Swollman } 45618316Swollman 45718316Swollman rip_input(&from, cc); 45818316Swollman continue; 45918316Swollman } 46018316Swollman 46118316Swollman if (cc < 0) { 46232502Scharnier if (errno == EINTR) 46318316Swollman continue; 46446303Smarkm perror("select"); 46546303Smarkm exit(1); 46618316Swollman } 46718316Swollman 46818316Swollman /* After a pause in responses, probe another host. 46918316Swollman * This reduces the intermingling of answers. 47018316Swollman */ 47118316Swollman while (*argv != 0 && 0 > out(*argv++)) 47218316Swollman answered++; 47318316Swollman 47418316Swollman /* continue until no more packets arrive 47518316Swollman * or we have heard from all hosts 47618316Swollman */ 47718316Swollman if (answered >= argc) 47818316Swollman break; 47918316Swollman 48018316Swollman /* or until we have waited a long time 48118316Swollman */ 48246303Smarkm if (gettimeofday(&now, 0) < 0) { 48346303Smarkm perror("gettimeofday(now)"); 48446303Smarkm exit(1); 48546303Smarkm } 48618316Swollman if (sent.tv_sec + wtime <= now.tv_sec) 48718316Swollman break; 48818316Swollman } 48918316Swollman 49018316Swollman /* fail if there was no answer */ 49118316Swollman exit (answered >= argc ? 0 : 1); 49218316Swollman} 49318316Swollman 49418316Swollman 49519880Swollman/* send to one host 49618316Swollman */ 49718316Swollmanstatic int 49846303Smarkmout(const char *host) 49918316Swollman{ 50018316Swollman struct sockaddr_in router; 50118316Swollman struct hostent *hp; 50218316Swollman 50318316Swollman if (gettimeofday(&sent, 0) < 0) { 50446303Smarkm perror("gettimeofday(sent)"); 50518316Swollman return -1; 50618316Swollman } 50718316Swollman 50846303Smarkm memset(&router, 0, sizeof(router)); 50918316Swollman router.sin_family = AF_INET; 51018316Swollman#ifdef _HAVE_SIN_LEN 51118316Swollman router.sin_len = sizeof(router); 51218316Swollman#endif 51318316Swollman if (!inet_aton(host, &router.sin_addr)) { 51418316Swollman hp = gethostbyname(host); 51518316Swollman if (hp == 0) { 51618316Swollman herror(host); 51718316Swollman return -1; 51818316Swollman } 51946303Smarkm memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr)); 52018316Swollman } 52118316Swollman router.sin_port = htons(RIP_PORT); 52218316Swollman 52346303Smarkm if (sendto(soc, &omsg_buf, omsg_len, 0, 52418316Swollman (struct sockaddr *)&router, sizeof(router)) < 0) { 52546303Smarkm perror(host); 52618316Swollman return -1; 52718316Swollman } 52818316Swollman 52918316Swollman return 0; 53018316Swollman} 53118316Swollman 53218316Swollman 53318316Swollman/* 53419880Swollman * Convert string to printable characters 53519880Swollman */ 53619880Swollmanstatic char * 53719880Swollmanqstring(u_char *s, int len) 53819880Swollman{ 53919880Swollman static char buf[8*20+1]; 54019880Swollman char *p; 54119880Swollman u_char *s2, c; 54219880Swollman 54319880Swollman 54419880Swollman for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 54519880Swollman c = *s++; 54619880Swollman if (c == '\0') { 54719880Swollman for (s2 = s+1; s2 < &s[len]; s2++) { 54819880Swollman if (*s2 != '\0') 54919880Swollman break; 55019880Swollman } 55119880Swollman if (s2 >= &s[len]) 55219880Swollman goto exit; 55319880Swollman } 55419880Swollman 55519880Swollman if (c >= ' ' && c < 0x7f && c != '\\') { 55619880Swollman *p++ = c; 55719880Swollman continue; 55819880Swollman } 55919880Swollman *p++ = '\\'; 56019880Swollman switch (c) { 56119880Swollman case '\\': 56219880Swollman *p++ = '\\'; 56319880Swollman break; 56419880Swollman case '\n': 56519880Swollman *p++= 'n'; 56619880Swollman break; 56719880Swollman case '\r': 56819880Swollman *p++= 'r'; 56919880Swollman break; 57019880Swollman case '\t': 57119880Swollman *p++ = 't'; 57219880Swollman break; 57319880Swollman case '\b': 57419880Swollman *p++ = 'b'; 57519880Swollman break; 57619880Swollman default: 57719880Swollman p += sprintf(p,"%o",c); 57819880Swollman break; 57919880Swollman } 58019880Swollman } 58119880Swollmanexit: 58219880Swollman *p = '\0'; 58319880Swollman return buf; 58419880Swollman} 58519880Swollman 58619880Swollman 58719880Swollman/* 58818316Swollman * Handle an incoming RIP packet. 58918316Swollman */ 59018316Swollmanstatic void 59118316Swollmanrip_input(struct sockaddr_in *from, 59218316Swollman int size) 59318316Swollman{ 59418316Swollman struct netinfo *n, *lim; 59518316Swollman struct in_addr in; 59646303Smarkm const char *name; 59718316Swollman char net_buf[80]; 59846303Smarkm u_char hash[RIP_AUTH_MD5_LEN]; 59946303Smarkm MD5_CTX md5_ctx; 60046303Smarkm u_char md5_authed = 0; 60118316Swollman u_int mask, dmask; 60218316Swollman char *sp; 60318316Swollman int i; 60418316Swollman struct hostent *hp; 60518316Swollman struct netent *np; 60619880Swollman struct netauth *na; 60718316Swollman 60818316Swollman 60918316Swollman if (nflag) { 61018316Swollman printf("%s:", inet_ntoa(from->sin_addr)); 61118316Swollman } else { 61218316Swollman hp = gethostbyaddr((char*)&from->sin_addr, 61318316Swollman sizeof(struct in_addr), AF_INET); 61418316Swollman if (hp == 0) { 61518316Swollman printf("%s:", 61618316Swollman inet_ntoa(from->sin_addr)); 61718316Swollman } else { 61818316Swollman printf("%s (%s):", hp->h_name, 61918316Swollman inet_ntoa(from->sin_addr)); 62018316Swollman } 62118316Swollman } 62218316Swollman if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 62318316Swollman printf("\n unexpected response type %d\n", IMSG.rip_cmd); 62418316Swollman return; 62518316Swollman } 62618316Swollman printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 62718316Swollman (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 62818316Swollman size); 62918316Swollman if (size > MAXPACKETSIZE) { 63046303Smarkm if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) { 63118316Swollman printf(" at least %d bytes too long\n", 63218316Swollman size-MAXPACKETSIZE); 63346303Smarkm size = (int)sizeof(imsg_buf) - (int)sizeof(*n); 63418316Swollman } else { 63518316Swollman printf(" %d bytes too long\n", 63618316Swollman size-MAXPACKETSIZE); 63718316Swollman } 63818316Swollman } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 63918316Swollman printf(" response of bad length=%d\n", size); 64018316Swollman } 64118316Swollman 64218316Swollman n = IMSG.rip_nets; 64318316Swollman lim = (struct netinfo *)((char*)n + size) - 1; 64418316Swollman for (; n <= lim; n++) { 64518316Swollman name = ""; 64618316Swollman if (n->n_family == RIP_AF_INET) { 64718316Swollman in.s_addr = n->n_dst; 64818316Swollman (void)strcpy(net_buf, inet_ntoa(in)); 64918316Swollman 65018316Swollman mask = ntohl(n->n_mask); 65118316Swollman dmask = mask & -mask; 65218316Swollman if (mask != 0) { 65318316Swollman sp = &net_buf[strlen(net_buf)]; 65418316Swollman if (IMSG.rip_vers == RIPv1) { 65518316Swollman (void)sprintf(sp," mask=%#x ? ",mask); 65618316Swollman mask = 0; 65718316Swollman } else if (mask + dmask == 0) { 65818316Swollman for (i = 0; 65918316Swollman (i != 32 66018316Swollman && ((1<<i)&mask) == 0); 66118316Swollman i++) 66218316Swollman continue; 66318316Swollman (void)sprintf(sp, "/%d",32-i); 66418316Swollman } else { 66518316Swollman (void)sprintf(sp," (mask %#x)", mask); 66618316Swollman } 66718316Swollman } 66818316Swollman 66918316Swollman if (!nflag) { 67018316Swollman if (mask == 0) { 67118316Swollman mask = std_mask(in.s_addr); 67218316Swollman if ((ntohl(in.s_addr) & ~mask) != 0) 67318316Swollman mask = 0; 67418316Swollman } 67518316Swollman /* Without a netmask, do not worry about 67618316Swollman * whether the destination is a host or a 67718316Swollman * network. Try both and use the first name 67818316Swollman * we get. 67918316Swollman * 68018316Swollman * If we have a netmask we can make a 68118316Swollman * good guess. 68218316Swollman */ 68318316Swollman if ((in.s_addr & ~mask) == 0) { 68418316Swollman np = getnetbyaddr((long)in.s_addr, 68518316Swollman AF_INET); 68618316Swollman if (np != 0) 68718316Swollman name = np->n_name; 68818316Swollman else if (in.s_addr == 0) 68918316Swollman name = "default"; 69018316Swollman } 69118316Swollman if (name[0] == '\0' 69218316Swollman && ((in.s_addr & ~mask) != 0 69318316Swollman || mask == 0xffffffff)) { 69418316Swollman hp = gethostbyaddr((char*)&in, 69518316Swollman sizeof(in), 69618316Swollman AF_INET); 69718316Swollman if (hp != 0) 69818316Swollman name = hp->h_name; 69918316Swollman } 70018316Swollman } 70118316Swollman 70218316Swollman } else if (n->n_family == RIP_AF_AUTH) { 70319880Swollman na = (struct netauth*)n; 70419880Swollman if (na->a_type == RIP_AUTH_PW 70519880Swollman && n == IMSG.rip_nets) { 70619880Swollman (void)printf(" Password Authentication:" 70719880Swollman " \"%s\"\n", 70819880Swollman qstring(na->au.au_pw, 70919880Swollman RIP_AUTH_PW_LEN)); 71019880Swollman continue; 71119880Swollman } 71219880Swollman 71319880Swollman if (na->a_type == RIP_AUTH_MD5 71419880Swollman && n == IMSG.rip_nets) { 71546303Smarkm (void)printf(" MD5 Auth" 71619880Swollman " len=%d KeyID=%d" 71746303Smarkm " auth_len=%d" 71846303Smarkm " seqno=%#x" 71919880Swollman " rsvd=%#x,%#x\n", 72046303Smarkm ntohs(na->au.a_md5.md5_pkt_len), 72119880Swollman na->au.a_md5.md5_keyid, 72246303Smarkm na->au.a_md5.md5_auth_len, 72346303Smarkm (int)ntohl(na->au.a_md5.md5_seqno), 72419880Swollman na->au.a_md5.rsvd[0], 72519880Swollman na->au.a_md5.rsvd[1]); 72646303Smarkm md5_authed = 1; 72719880Swollman continue; 72819880Swollman } 72919880Swollman (void)printf(" Authentication type %d: ", 73019880Swollman ntohs(na->a_type)); 73146303Smarkm for (i = 0; i < (int)sizeof(na->au.au_pw); i++) 73219880Swollman (void)printf("%02x ", na->au.au_pw[i]); 73318316Swollman putc('\n', stdout); 73446303Smarkm if (md5_authed && n+1 > lim 73546303Smarkm && na->a_type == ntohs(1)) { 73646303Smarkm MD5Init(&md5_ctx); 73746303Smarkm MD5Update(&md5_ctx, (u_char *)&IMSG, 73846303Smarkm (char *)na-(char *)&IMSG); 73946303Smarkm MD5Update(&md5_ctx, (u_char *)passwd, 74046303Smarkm RIP_AUTH_MD5_LEN); 74146303Smarkm MD5Final(hash, &md5_ctx); 74246303Smarkm (void)printf(" %s hash\n", 74346303Smarkm memcmp(hash, na->au.au_pw, 74446303Smarkm sizeof(hash)) 74546303Smarkm ? "WRONG" : "correct"); 74646303Smarkm } 74718316Swollman continue; 74818316Swollman 74918316Swollman } else { 75018316Swollman (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 75118316Swollman ntohs(n->n_family), 75218316Swollman (char)(n->n_dst >> 24), 75318316Swollman (char)(n->n_dst >> 16), 75418316Swollman (char)(n->n_dst >> 8), 75518316Swollman (char)n->n_dst); 75618316Swollman } 75718316Swollman 75818316Swollman (void)printf(" %-18s metric %2d %-10s", 75946303Smarkm net_buf, (int)ntohl(n->n_metric), name); 76018316Swollman 76118316Swollman if (n->n_nhop != 0) { 76218316Swollman in.s_addr = n->n_nhop; 76318316Swollman if (nflag) 76418316Swollman hp = 0; 76518316Swollman else 76618316Swollman hp = gethostbyaddr((char*)&in, sizeof(in), 76718316Swollman AF_INET); 76818316Swollman (void)printf(" nhop=%-15s%s", 76918316Swollman (hp != 0) ? hp->h_name : inet_ntoa(in), 77018316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 77118316Swollman } 77218316Swollman if (n->n_tag != 0) 77318316Swollman (void)printf(" tag=%#x%s", n->n_tag, 77418316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 77518316Swollman putc('\n', stdout); 77618316Swollman } 77718316Swollman} 77818316Swollman 77918316Swollman 78018316Swollman/* Return the classical netmask for an IP address. 78118316Swollman */ 78218316Swollmanstatic u_int 78318316Swollmanstd_mask(u_int addr) /* in network order */ 78418316Swollman{ 78518316Swollman NTOHL(addr); /* was a host, not a network */ 78618316Swollman 78718316Swollman if (addr == 0) /* default route has mask 0 */ 78818316Swollman return 0; 78918316Swollman if (IN_CLASSA(addr)) 79018316Swollman return IN_CLASSA_NET; 79118316Swollman if (IN_CLASSB(addr)) 79218316Swollman return IN_CLASSB_NET; 79318316Swollman return IN_CLASSC_NET; 79418316Swollman} 79518316Swollman 79618316Swollman 79718316Swollman/* get a network number as a name or a number, with an optional "/xx" 79818316Swollman * netmask. 79918316Swollman */ 80018316Swollmanstatic int /* 0=bad */ 80118316Swollmangetnet(char *name, 80218316Swollman struct netinfo *rt) 80318316Swollman{ 80418316Swollman int i; 80518316Swollman struct netent *nentp; 80618316Swollman u_int mask; 80718316Swollman struct in_addr in; 80818316Swollman char hname[MAXHOSTNAMELEN+1]; 80918316Swollman char *mname, *p; 81018316Swollman 81118316Swollman 81218316Swollman /* Detect and separate "1.2.3.4/24" 81318316Swollman */ 81446303Smarkm if (0 != (mname = strrchr(name,'/'))) { 81518316Swollman i = (int)(mname - name); 81646303Smarkm if (i > (int)sizeof(hname)-1) /* name too long */ 81718316Swollman return 0; 81846303Smarkm memmove(hname, name, i); 81918316Swollman hname[i] = '\0'; 82018316Swollman mname++; 82118316Swollman name = hname; 82218316Swollman } 82318316Swollman 82418316Swollman nentp = getnetbyname(name); 82518316Swollman if (nentp != 0) { 82618316Swollman in.s_addr = nentp->n_net; 82718316Swollman } else if (inet_aton(name, &in) == 1) { 82818316Swollman NTOHL(in.s_addr); 82918316Swollman } else { 83018316Swollman return 0; 83118316Swollman } 83218316Swollman 83318316Swollman if (mname == 0) { 83418316Swollman mask = std_mask(in.s_addr); 83518316Swollman if ((~mask & in.s_addr) != 0) 83618316Swollman mask = 0xffffffff; 83718316Swollman } else { 83818316Swollman mask = (u_int)strtoul(mname, &p, 0); 83918316Swollman if (*p != '\0' || mask > 32) 84018316Swollman return 0; 84118316Swollman mask = 0xffffffff << (32-mask); 84218316Swollman } 84318316Swollman 84418316Swollman rt->n_dst = htonl(in.s_addr); 84518316Swollman rt->n_family = RIP_AF_INET; 84618316Swollman rt->n_mask = htonl(mask); 84718316Swollman return 1; 84818316Swollman} 84919880Swollman 85019880Swollman 85119880Swollman/* strtok(), but honoring backslash 85219880Swollman */ 85319880Swollmanstatic int /* -1=bad */ 85419880Swollmanparse_quote(char **linep, 85546303Smarkm const char *delims, 85619880Swollman char *delimp, 85719880Swollman char *buf, 85819880Swollman int lim) 85919880Swollman{ 86046303Smarkm char c, *pc; 86146303Smarkm const char *p; 86219880Swollman 86319880Swollman 86419880Swollman pc = *linep; 86519880Swollman if (*pc == '\0') 86619880Swollman return -1; 86719880Swollman 86819880Swollman for (;;) { 86919880Swollman if (lim == 0) 87019880Swollman return -1; 87119880Swollman c = *pc++; 87219880Swollman if (c == '\0') 87319880Swollman break; 87419880Swollman 87537815Sphk if (c == '\\' && *pc != '\0') { 87619880Swollman if ((c = *pc++) == 'n') { 87719880Swollman c = '\n'; 87819880Swollman } else if (c == 'r') { 87919880Swollman c = '\r'; 88019880Swollman } else if (c == 't') { 88119880Swollman c = '\t'; 88219880Swollman } else if (c == 'b') { 88319880Swollman c = '\b'; 88419880Swollman } else if (c >= '0' && c <= '7') { 88519880Swollman c -= '0'; 88619880Swollman if (*pc >= '0' && *pc <= '7') { 88719880Swollman c = (c<<3)+(*pc++ - '0'); 88819880Swollman if (*pc >= '0' && *pc <= '7') 88919880Swollman c = (c<<3)+(*pc++ - '0'); 89019880Swollman } 89119880Swollman } 89219880Swollman 89319880Swollman } else { 89419880Swollman for (p = delims; *p != '\0'; ++p) { 89519880Swollman if (*p == c) 89619880Swollman goto exit; 89719880Swollman } 89819880Swollman } 89919880Swollman 90019880Swollman *buf++ = c; 90119880Swollman --lim; 90219880Swollman } 90319880Swollmanexit: 90419880Swollman if (delimp != 0) 90519880Swollman *delimp = c; 90619880Swollman *linep = pc-1; 90719880Swollman if (lim != 0) 90819880Swollman *buf = '\0'; 90919880Swollman return 0; 91019880Swollman} 911