rtquery.c revision 126250
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 * 3350476Speter * $FreeBSD: head/sbin/routed/rtquery/rtquery.c 126250 2004-02-25 23:45:57Z bms $ 3418316Swollman */ 3518316Swollman 3646303Smarkm#include <sys/cdefs.h> 3718316Swollman#include <sys/param.h> 3846303Smarkm#include <sys/protosw.h> 3918316Swollman#include <sys/socket.h> 4018316Swollman#include <sys/time.h> 4118316Swollman#include <netinet/in.h> 4218316Swollman#define RIPVERSION RIPv2 4318316Swollman#include <protocols/routed.h> 4418316Swollman#include <arpa/inet.h> 4546303Smarkm#include <netdb.h> 4632502Scharnier#include <errno.h> 4746303Smarkm#include <unistd.h> 4818316Swollman#include <stdio.h> 4918316Swollman#include <stdlib.h> 5018316Swollman#include <string.h> 5118316Swollman#ifdef sgi 5218316Swollman#include <strings.h> 5318316Swollman#include <bstring.h> 5418316Swollman#endif 5518316Swollman 56126250Sbms#define UNUSED __attribute__((unused)) 57126250Sbms#ifndef __RCSID 58126250Sbms#define __RCSID(_s) static const char rcsid[] UNUSED = _s 5946303Smarkm#endif 60126250Sbms#ifndef __COPYRIGHT 61126250Sbms#define __COPYRIGHT(_s) static const char copyright[] UNUSED = _s 62126250Sbms#endif 63126250Sbms__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n" 64126250Sbms "The Regents of the University of California." 65126250Sbms " All rights reserved.\n"); 66126250Sbms#ifdef __NetBSD__ 67126250Sbms__RCSID("$NetBSD$"); 68126250Sbms#elif defined(__FreeBSD__) 69126250Sbms__RCSID("$FreeBSD: head/sbin/routed/rtquery/rtquery.c 126250 2004-02-25 23:45:57Z bms $"); 70126250Sbms#else 71126250Sbms__RCSID("$Revision: 2.26 $"); 72126250Sbms#ident "$Revision: 2.26 $" 73126250Sbms#endif 7446303Smarkm 7518316Swollman#ifndef sgi 7618316Swollman#define _HAVE_SIN_LEN 7718316Swollman#endif 7818316Swollman 79126250Sbms#ifdef __NetBSD__ 80126250Sbms#include <md5.h> 81126250Sbms#else 8246303Smarkm#define MD5_DIGEST_LEN 16 8346303Smarkmtypedef struct { 8446303Smarkm u_int32_t state[4]; /* state (ABCD) */ 8546303Smarkm u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ 8646303Smarkm unsigned char buffer[64]; /* input buffer */ 8746303Smarkm} MD5_CTX; 8846303Smarkmextern void MD5Init(MD5_CTX*); 8946303Smarkmextern void MD5Update(MD5_CTX*, u_char*, u_int); 9046303Smarkmextern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); 91126250Sbms#endif 9246303Smarkm 9346303Smarkm 9418316Swollman#define WTIME 15 /* Time to wait for all responses */ 9518316Swollman#define STIME (250*1000) /* usec to wait for another response */ 9618316Swollman 9746303Smarkmint soc; 9818316Swollman 9946303Smarkmconst char *pgmname; 10046303Smarkm 10118316Swollmanunion { 10218316Swollman struct rip rip; 10318316Swollman char packet[MAXPACKETSIZE+MAXPATHLEN]; 10418316Swollman} omsg_buf; 10518316Swollman#define OMSG omsg_buf.rip 10618316Swollmanint omsg_len = sizeof(struct rip); 10718316Swollman 10818316Swollmanunion { 10918316Swollman struct rip rip; 11018316Swollman char packet[MAXPACKETSIZE+1024]; 11118316Swollman } imsg_buf; 11218316Swollman#define IMSG imsg_buf.rip 11318316Swollman 11418316Swollmanint nflag; /* numbers, no names */ 11518316Swollmanint pflag; /* play the `gated` game */ 11618316Swollmanint ripv2 = 1; /* use RIP version 2 */ 11718316Swollmanint wtime = WTIME; 11818316Swollmanint rflag; /* 1=ask about a particular route */ 11919880Swollmanint trace, not_trace; /* send trace command or not */ 12019880Swollmanint auth_type = RIP_AUTH_NONE; 12119880Swollmanchar passwd[RIP_AUTH_PW_LEN]; 12219880Swollmanu_long keyid; 12318316Swollman 12418316Swollmanstruct timeval sent; /* when query sent */ 12518316Swollman 12646303Smarkmstatic char localhost_str[] = "localhost"; 12746303Smarkmstatic char *default_argv[] = {localhost_str, 0}; 12846303Smarkm 12918316Swollmanstatic void rip_input(struct sockaddr_in*, int); 13046303Smarkmstatic int out(const char *); 13146303Smarkmstatic void trace_loop(char *argv[]) __attribute((__noreturn__)); 13246303Smarkmstatic void query_loop(char *argv[], int) __attribute((__noreturn__)); 13318316Swollmanstatic int getnet(char *, struct netinfo *); 13418316Swollmanstatic u_int std_mask(u_int); 13546303Smarkmstatic int parse_quote(char **, const char *, char *, char *, int); 13637908Scharnierstatic void usage(void); 13718316Swollman 13846303Smarkm 13937908Scharnierint 14018316Swollmanmain(int argc, 14118316Swollman char *argv[]) 14218316Swollman{ 14318316Swollman int ch, bsize; 14419880Swollman char *p, *options, *value, delim; 14546303Smarkm const char *result; 14618316Swollman 14718316Swollman OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 14818316Swollman OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 14918316Swollman OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 15018316Swollman 15146303Smarkm pgmname = argv[0]; 15224359Simp while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) 15318316Swollman switch (ch) { 15418316Swollman case 'n': 15518316Swollman not_trace = 1; 15618316Swollman nflag = 1; 15718316Swollman break; 15818316Swollman 15918316Swollman case 'p': 16018316Swollman not_trace = 1; 16118316Swollman pflag = 1; 16218316Swollman break; 16318316Swollman 16418316Swollman case '1': 16518316Swollman ripv2 = 0; 16618316Swollman break; 16718316Swollman 16818316Swollman case 'w': 16918316Swollman not_trace = 1; 17018316Swollman wtime = (int)strtoul(optarg, &p, 0); 17118316Swollman if (*p != '\0' 17218316Swollman || wtime <= 0) 17337908Scharnier usage(); 17418316Swollman break; 17518316Swollman 17618316Swollman case 'r': 17718316Swollman not_trace = 1; 17818316Swollman if (rflag) 17937908Scharnier usage(); 18018316Swollman rflag = getnet(optarg, &OMSG.rip_nets[0]); 18118316Swollman if (!rflag) { 18218316Swollman struct hostent *hp = gethostbyname(optarg); 18346303Smarkm if (hp == 0) { 18446303Smarkm fprintf(stderr, "%s: %s:", 18546303Smarkm pgmname, optarg); 18646303Smarkm herror(0); 18746303Smarkm exit(1); 18846303Smarkm } 18946303Smarkm memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr, 19046303Smarkm sizeof(OMSG.rip_nets[0].n_dst)); 19118316Swollman OMSG.rip_nets[0].n_family = RIP_AF_INET; 19218316Swollman OMSG.rip_nets[0].n_mask = -1; 19318316Swollman rflag = 1; 19418316Swollman } 19518316Swollman break; 19618316Swollman 19718316Swollman case 't': 19818316Swollman trace = 1; 19918316Swollman options = optarg; 20018316Swollman while (*options != '\0') { 20146303Smarkm /* messy complications to make -W -Wall happy */ 20246303Smarkm static char on_str[] = "on"; 20346303Smarkm static char more_str[] = "more"; 20446303Smarkm static char off_str[] = "off"; 20546303Smarkm static char dump_str[] = "dump"; 20646303Smarkm static char *traceopts[] = { 20718316Swollman# define TRACE_ON 0 20846303Smarkm on_str, 20918316Swollman# define TRACE_MORE 1 21046303Smarkm more_str, 21118316Swollman# define TRACE_OFF 2 21246303Smarkm off_str, 21318316Swollman# define TRACE_DUMP 3 21446303Smarkm dump_str, 21518316Swollman 0 21618316Swollman }; 21746303Smarkm result = ""; 21818316Swollman switch (getsubopt(&options,traceopts,&value)) { 21918316Swollman case TRACE_ON: 22018316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 22118316Swollman if (!value 22218316Swollman || strlen(value) > MAXPATHLEN) 22346303Smarkm usage(); 22446303Smarkm result = value; 22518316Swollman break; 22618316Swollman case TRACE_MORE: 22718316Swollman if (value) 22846303Smarkm usage(); 22918316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 23018316Swollman break; 23118316Swollman case TRACE_OFF: 23218316Swollman if (value) 23346303Smarkm usage(); 23418316Swollman OMSG.rip_cmd = RIPCMD_TRACEOFF; 23518316Swollman break; 23618316Swollman case TRACE_DUMP: 23718316Swollman if (value) 23846303Smarkm usage(); 23918316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 24046303Smarkm result = "dump/../table"; 24118316Swollman break; 24218316Swollman default: 24337908Scharnier usage(); 24418316Swollman } 24546303Smarkm strcpy((char*)OMSG.rip_tracefile, result); 24646303Smarkm omsg_len += strlen(result) - sizeof(OMSG.ripun); 24718316Swollman } 24818316Swollman break; 24918316Swollman 25019880Swollman case 'a': 25119880Swollman not_trace = 1; 25219880Swollman p = strchr(optarg,'='); 25319880Swollman if (!p) 25437908Scharnier usage(); 25519880Swollman *p++ = '\0'; 25619880Swollman if (!strcasecmp("passwd",optarg)) 25719880Swollman auth_type = RIP_AUTH_PW; 25819880Swollman else if (!strcasecmp("md5_passwd",optarg)) 25919880Swollman auth_type = RIP_AUTH_MD5; 26019880Swollman else 26137908Scharnier usage(); 26219880Swollman if (0 > parse_quote(&p,"|",&delim, 26346303Smarkm passwd, sizeof(passwd))) 26437908Scharnier usage(); 26519880Swollman if (auth_type == RIP_AUTH_MD5 26619880Swollman && delim == '|') { 26719880Swollman keyid = strtoul(p+1,&p,0); 26819880Swollman if (keyid > 255 || *p != '\0') 26937908Scharnier usage(); 27019880Swollman } else if (delim != '\0') { 27137908Scharnier usage(); 27219880Swollman } 27319880Swollman break; 27419880Swollman 27518316Swollman default: 27637908Scharnier usage(); 27718316Swollman } 27818316Swollman argv += optind; 27918316Swollman argc -= optind; 28046303Smarkm if (not_trace && trace) 28137908Scharnier usage(); 28246303Smarkm if (argc == 0) { 28346303Smarkm argc = 1; 28446303Smarkm argv = default_argv; 28546303Smarkm } 28618316Swollman 28746303Smarkm soc = socket(AF_INET, SOCK_DGRAM, 0); 28846303Smarkm if (soc < 0) { 28946524Smarkm perror("socket"); 29046524Smarkm exit(2); 29146303Smarkm } 29218316Swollman 29318316Swollman /* be prepared to receive a lot of routes */ 29418316Swollman for (bsize = 127*1024; ; bsize -= 1024) { 29546303Smarkm if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF, 29618316Swollman &bsize, sizeof(bsize)) == 0) 29718316Swollman break; 29818316Swollman if (bsize <= 4*1024) { 29946524Smarkm perror("setsockopt SO_RCVBUF"); 30018316Swollman break; 30118316Swollman } 30218316Swollman } 30318316Swollman 30418316Swollman if (trace) 30518316Swollman trace_loop(argv); 30618316Swollman else 30718316Swollman query_loop(argv, argc); 30818316Swollman /* NOTREACHED */ 30946303Smarkm return 0; 31018316Swollman} 31118316Swollman 31246303Smarkm 31337908Scharnierstatic void 31446303Smarkmusage(void) 31537908Scharnier{ 31646303Smarkm fprintf(stderr, 31746303Smarkm "usage: rtquery [-np1] [-r tgt_rt] [-w wtime]" 31846303Smarkm " [-a type=passwd] host1 [host2 ...]\n" 31946303Smarkm "\trtquery -t {on=filename|more|off|dump}" 32046303Smarkm " host1 [host2 ...]\n"); 32137908Scharnier exit(1); 32237908Scharnier} 32318316Swollman 32446303Smarkm 32518316Swollman/* tell the target hosts about tracing 32618316Swollman */ 32718316Swollmanstatic void 32818316Swollmantrace_loop(char *argv[]) 32918316Swollman{ 33018316Swollman struct sockaddr_in myaddr; 33118316Swollman int res; 33218316Swollman 33346303Smarkm if (geteuid() != 0) { 33446303Smarkm (void)fprintf(stderr, "-t requires UID 0\n"); 33546303Smarkm exit(1); 33646303Smarkm } 33718316Swollman 33818316Swollman if (ripv2) { 33918316Swollman OMSG.rip_vers = RIPv2; 34018316Swollman } else { 34118316Swollman OMSG.rip_vers = RIPv1; 34218316Swollman } 34318316Swollman 34446303Smarkm memset(&myaddr, 0, sizeof(myaddr)); 34518316Swollman myaddr.sin_family = AF_INET; 34618316Swollman#ifdef _HAVE_SIN_LEN 34718316Swollman myaddr.sin_len = sizeof(myaddr); 34818316Swollman#endif 34918316Swollman myaddr.sin_port = htons(IPPORT_RESERVED-1); 35046303Smarkm while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 35146303Smarkm if (errno != EADDRINUSE 35246303Smarkm || myaddr.sin_port == 0) { 35346524Smarkm perror("bind"); 35446524Smarkm exit(2); 35546303Smarkm } 35618316Swollman myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 35718316Swollman } 35818316Swollman 35918316Swollman res = 1; 36018316Swollman while (*argv != 0) { 36118316Swollman if (out(*argv++) <= 0) 36218316Swollman res = 0; 36318316Swollman } 36418316Swollman exit(res); 36518316Swollman} 36618316Swollman 36718316Swollman 36818316Swollman/* query all of the listed hosts 36918316Swollman */ 37018316Swollmanstatic void 37118316Swollmanquery_loop(char *argv[], int argc) 37218316Swollman{ 37319880Swollman# define NA0 (OMSG.rip_auths[0]) 37419880Swollman# define NA2 (OMSG.rip_auths[2]) 37518316Swollman struct seen { 37618316Swollman struct seen *next; 37718316Swollman struct in_addr addr; 37818316Swollman } *seen, *sp; 37918316Swollman int answered = 0; 38018316Swollman int cc; 38118316Swollman fd_set bits; 38218316Swollman struct timeval now, delay; 38318316Swollman struct sockaddr_in from; 38418316Swollman int fromlen; 38519880Swollman MD5_CTX md5_ctx; 38618316Swollman 38718316Swollman 38818316Swollman OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 38918316Swollman if (ripv2) { 39018316Swollman OMSG.rip_vers = RIPv2; 39119880Swollman if (auth_type == RIP_AUTH_PW) { 39219880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 39319880Swollman NA0.a_family = RIP_AF_AUTH; 39419880Swollman NA0.a_type = RIP_AUTH_PW; 39546303Smarkm memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN); 39619880Swollman omsg_len += sizeof(OMSG.rip_nets[0]); 39719880Swollman 39819880Swollman } else if (auth_type == RIP_AUTH_MD5) { 39919880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 40019880Swollman NA0.a_family = RIP_AF_AUTH; 40119880Swollman NA0.a_type = RIP_AUTH_MD5; 40219880Swollman NA0.au.a_md5.md5_keyid = (int8_t)keyid; 403126250Sbms NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN; 40419880Swollman NA0.au.a_md5.md5_seqno = 0; 40546303Smarkm cc = (char *)&NA2-(char *)&OMSG; 40646303Smarkm NA0.au.a_md5.md5_pkt_len = htons(cc); 40719880Swollman NA2.a_family = RIP_AF_AUTH; 40846303Smarkm NA2.a_type = htons(1); 40919880Swollman MD5Init(&md5_ctx); 41046303Smarkm MD5Update(&md5_ctx, 41146303Smarkm (u_char *)&OMSG, cc); 41246303Smarkm MD5Update(&md5_ctx, 413126250Sbms (u_char *)passwd, RIP_AUTH_MD5_HASH_LEN); 41419880Swollman MD5Final(NA2.au.au_pw, &md5_ctx); 41519880Swollman omsg_len += 2*sizeof(OMSG.rip_nets[0]); 41619880Swollman } 41719880Swollman 41818316Swollman } else { 41918316Swollman OMSG.rip_vers = RIPv1; 42018316Swollman OMSG.rip_nets[0].n_mask = 0; 42118316Swollman } 42218316Swollman 42318316Swollman /* ask the first (valid) host */ 42418316Swollman seen = 0; 42518316Swollman while (0 > out(*argv++)) { 42618316Swollman if (*argv == 0) 427126250Sbms exit(1); 42818316Swollman answered++; 42918316Swollman } 43018316Swollman 43118316Swollman FD_ZERO(&bits); 43218316Swollman for (;;) { 43346303Smarkm FD_SET(soc, &bits); 43418316Swollman delay.tv_sec = 0; 43518316Swollman delay.tv_usec = STIME; 43646303Smarkm cc = select(soc+1, &bits, 0,0, &delay); 43718316Swollman if (cc > 0) { 43818316Swollman fromlen = sizeof(from); 43946303Smarkm cc = recvfrom(soc, imsg_buf.packet, 44018316Swollman sizeof(imsg_buf.packet), 0, 44118316Swollman (struct sockaddr *)&from, &fromlen); 44246303Smarkm if (cc < 0) { 44346524Smarkm perror("recvfrom"); 44446524Smarkm exit(1); 44546303Smarkm } 44618316Swollman /* count the distinct responding hosts. 44718316Swollman * You cannot match responding hosts with 44818316Swollman * addresses to which queries were transmitted, 44918316Swollman * because a router might respond with a 45018316Swollman * different source address. 45118316Swollman */ 45218316Swollman for (sp = seen; sp != 0; sp = sp->next) { 45318316Swollman if (sp->addr.s_addr == from.sin_addr.s_addr) 45418316Swollman break; 45518316Swollman } 45618316Swollman if (sp == 0) { 45718316Swollman sp = malloc(sizeof(*sp)); 45846303Smarkm if (sp == 0) { 45946303Smarkm fprintf(stderr, 46046303Smarkm "rtquery: malloc failed\n"); 46146303Smarkm exit(1); 46246303Smarkm } 46318316Swollman sp->addr = from.sin_addr; 46418316Swollman sp->next = seen; 46518316Swollman seen = sp; 46618316Swollman answered++; 46718316Swollman } 46818316Swollman 46918316Swollman rip_input(&from, cc); 47018316Swollman continue; 47118316Swollman } 47218316Swollman 47318316Swollman if (cc < 0) { 47432502Scharnier if (errno == EINTR) 47518316Swollman continue; 47646524Smarkm perror("select"); 47746524Smarkm exit(1); 47818316Swollman } 47918316Swollman 48018316Swollman /* After a pause in responses, probe another host. 48118316Swollman * This reduces the intermingling of answers. 48218316Swollman */ 48318316Swollman while (*argv != 0 && 0 > out(*argv++)) 48418316Swollman answered++; 48518316Swollman 48618316Swollman /* continue until no more packets arrive 48718316Swollman * or we have heard from all hosts 48818316Swollman */ 48918316Swollman if (answered >= argc) 49018316Swollman break; 49118316Swollman 49218316Swollman /* or until we have waited a long time 49318316Swollman */ 49446303Smarkm if (gettimeofday(&now, 0) < 0) { 49546524Smarkm perror("gettimeofday(now)"); 49646524Smarkm exit(1); 49746303Smarkm } 49818316Swollman if (sent.tv_sec + wtime <= now.tv_sec) 49918316Swollman break; 50018316Swollman } 50118316Swollman 50218316Swollman /* fail if there was no answer */ 50318316Swollman exit (answered >= argc ? 0 : 1); 50418316Swollman} 50518316Swollman 50618316Swollman 50719880Swollman/* send to one host 50818316Swollman */ 50918316Swollmanstatic int 51046303Smarkmout(const char *host) 51118316Swollman{ 51218316Swollman struct sockaddr_in router; 51318316Swollman struct hostent *hp; 51418316Swollman 51518316Swollman if (gettimeofday(&sent, 0) < 0) { 51646524Smarkm perror("gettimeofday(sent)"); 51746524Smarkm return -1; 51818316Swollman } 51918316Swollman 52046303Smarkm memset(&router, 0, sizeof(router)); 52118316Swollman router.sin_family = AF_INET; 52218316Swollman#ifdef _HAVE_SIN_LEN 52318316Swollman router.sin_len = sizeof(router); 52418316Swollman#endif 52518316Swollman if (!inet_aton(host, &router.sin_addr)) { 52618316Swollman hp = gethostbyname(host); 52718316Swollman if (hp == 0) { 52818316Swollman herror(host); 52918316Swollman return -1; 53018316Swollman } 53146303Smarkm memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr)); 53218316Swollman } 53318316Swollman router.sin_port = htons(RIP_PORT); 53418316Swollman 53546303Smarkm if (sendto(soc, &omsg_buf, omsg_len, 0, 53618316Swollman (struct sockaddr *)&router, sizeof(router)) < 0) { 53746524Smarkm perror(host); 53846524Smarkm return -1; 53918316Swollman } 54018316Swollman 54118316Swollman return 0; 54218316Swollman} 54318316Swollman 54418316Swollman 54518316Swollman/* 54619880Swollman * Convert string to printable characters 54719880Swollman */ 54819880Swollmanstatic char * 54919880Swollmanqstring(u_char *s, int len) 55019880Swollman{ 55119880Swollman static char buf[8*20+1]; 55219880Swollman char *p; 55319880Swollman u_char *s2, c; 55419880Swollman 55519880Swollman 55619880Swollman for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 55719880Swollman c = *s++; 55819880Swollman if (c == '\0') { 55919880Swollman for (s2 = s+1; s2 < &s[len]; s2++) { 56019880Swollman if (*s2 != '\0') 56119880Swollman break; 56219880Swollman } 56319880Swollman if (s2 >= &s[len]) 56419880Swollman goto exit; 56519880Swollman } 56619880Swollman 56719880Swollman if (c >= ' ' && c < 0x7f && c != '\\') { 56819880Swollman *p++ = c; 56919880Swollman continue; 57019880Swollman } 57119880Swollman *p++ = '\\'; 57219880Swollman switch (c) { 57319880Swollman case '\\': 57419880Swollman *p++ = '\\'; 57519880Swollman break; 57619880Swollman case '\n': 57719880Swollman *p++= 'n'; 57819880Swollman break; 57919880Swollman case '\r': 58019880Swollman *p++= 'r'; 58119880Swollman break; 58219880Swollman case '\t': 58319880Swollman *p++ = 't'; 58419880Swollman break; 58519880Swollman case '\b': 58619880Swollman *p++ = 'b'; 58719880Swollman break; 58819880Swollman default: 58919880Swollman p += sprintf(p,"%o",c); 59019880Swollman break; 59119880Swollman } 59219880Swollman } 59319880Swollmanexit: 59419880Swollman *p = '\0'; 59519880Swollman return buf; 59619880Swollman} 59719880Swollman 59819880Swollman 59919880Swollman/* 60018316Swollman * Handle an incoming RIP packet. 60118316Swollman */ 60218316Swollmanstatic void 60318316Swollmanrip_input(struct sockaddr_in *from, 60418316Swollman int size) 60518316Swollman{ 60618316Swollman struct netinfo *n, *lim; 60718316Swollman struct in_addr in; 60846303Smarkm const char *name; 60918316Swollman char net_buf[80]; 610126250Sbms u_char hash[RIP_AUTH_MD5_KEY_LEN]; 61146303Smarkm MD5_CTX md5_ctx; 61246303Smarkm u_char md5_authed = 0; 61318316Swollman u_int mask, dmask; 61418316Swollman char *sp; 61518316Swollman int i; 61618316Swollman struct hostent *hp; 61718316Swollman struct netent *np; 61819880Swollman struct netauth *na; 61918316Swollman 62018316Swollman 62118316Swollman if (nflag) { 62218316Swollman printf("%s:", inet_ntoa(from->sin_addr)); 62318316Swollman } else { 62418316Swollman hp = gethostbyaddr((char*)&from->sin_addr, 62518316Swollman sizeof(struct in_addr), AF_INET); 62618316Swollman if (hp == 0) { 62718316Swollman printf("%s:", 62818316Swollman inet_ntoa(from->sin_addr)); 62918316Swollman } else { 63018316Swollman printf("%s (%s):", hp->h_name, 63118316Swollman inet_ntoa(from->sin_addr)); 63218316Swollman } 63318316Swollman } 63418316Swollman if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 63518316Swollman printf("\n unexpected response type %d\n", IMSG.rip_cmd); 63618316Swollman return; 63718316Swollman } 63818316Swollman printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 63918316Swollman (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 64018316Swollman size); 64118316Swollman if (size > MAXPACKETSIZE) { 64246303Smarkm if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) { 64318316Swollman printf(" at least %d bytes too long\n", 64418316Swollman size-MAXPACKETSIZE); 64546303Smarkm size = (int)sizeof(imsg_buf) - (int)sizeof(*n); 64618316Swollman } else { 64718316Swollman printf(" %d bytes too long\n", 64818316Swollman size-MAXPACKETSIZE); 64918316Swollman } 65018316Swollman } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 65118316Swollman printf(" response of bad length=%d\n", size); 65218316Swollman } 65318316Swollman 65418316Swollman n = IMSG.rip_nets; 65518316Swollman lim = (struct netinfo *)((char*)n + size) - 1; 65618316Swollman for (; n <= lim; n++) { 65718316Swollman name = ""; 65818316Swollman if (n->n_family == RIP_AF_INET) { 65918316Swollman in.s_addr = n->n_dst; 66018316Swollman (void)strcpy(net_buf, inet_ntoa(in)); 66118316Swollman 66218316Swollman mask = ntohl(n->n_mask); 66318316Swollman dmask = mask & -mask; 66418316Swollman if (mask != 0) { 66518316Swollman sp = &net_buf[strlen(net_buf)]; 66618316Swollman if (IMSG.rip_vers == RIPv1) { 66718316Swollman (void)sprintf(sp," mask=%#x ? ",mask); 66818316Swollman mask = 0; 66918316Swollman } else if (mask + dmask == 0) { 67018316Swollman for (i = 0; 67118316Swollman (i != 32 67218316Swollman && ((1<<i)&mask) == 0); 67318316Swollman i++) 67418316Swollman continue; 67518316Swollman (void)sprintf(sp, "/%d",32-i); 67618316Swollman } else { 67718316Swollman (void)sprintf(sp," (mask %#x)", mask); 67818316Swollman } 67918316Swollman } 68018316Swollman 68118316Swollman if (!nflag) { 68218316Swollman if (mask == 0) { 68318316Swollman mask = std_mask(in.s_addr); 68418316Swollman if ((ntohl(in.s_addr) & ~mask) != 0) 68518316Swollman mask = 0; 68618316Swollman } 68718316Swollman /* Without a netmask, do not worry about 68818316Swollman * whether the destination is a host or a 68918316Swollman * network. Try both and use the first name 69018316Swollman * we get. 69118316Swollman * 69218316Swollman * If we have a netmask we can make a 69318316Swollman * good guess. 69418316Swollman */ 69518316Swollman if ((in.s_addr & ~mask) == 0) { 69618316Swollman np = getnetbyaddr((long)in.s_addr, 69718316Swollman AF_INET); 69818316Swollman if (np != 0) 69918316Swollman name = np->n_name; 70018316Swollman else if (in.s_addr == 0) 70118316Swollman name = "default"; 70218316Swollman } 70318316Swollman if (name[0] == '\0' 70418316Swollman && ((in.s_addr & ~mask) != 0 70518316Swollman || mask == 0xffffffff)) { 70618316Swollman hp = gethostbyaddr((char*)&in, 70718316Swollman sizeof(in), 70818316Swollman AF_INET); 70918316Swollman if (hp != 0) 71018316Swollman name = hp->h_name; 71118316Swollman } 71218316Swollman } 71318316Swollman 71418316Swollman } else if (n->n_family == RIP_AF_AUTH) { 71519880Swollman na = (struct netauth*)n; 71619880Swollman if (na->a_type == RIP_AUTH_PW 71719880Swollman && n == IMSG.rip_nets) { 71819880Swollman (void)printf(" Password Authentication:" 71919880Swollman " \"%s\"\n", 72019880Swollman qstring(na->au.au_pw, 72119880Swollman RIP_AUTH_PW_LEN)); 72219880Swollman continue; 72319880Swollman } 72419880Swollman 72519880Swollman if (na->a_type == RIP_AUTH_MD5 72619880Swollman && n == IMSG.rip_nets) { 72746303Smarkm (void)printf(" MD5 Auth" 72819880Swollman " len=%d KeyID=%d" 72946303Smarkm " auth_len=%d" 73046303Smarkm " seqno=%#x" 73119880Swollman " rsvd=%#x,%#x\n", 73246303Smarkm ntohs(na->au.a_md5.md5_pkt_len), 73319880Swollman na->au.a_md5.md5_keyid, 73446303Smarkm na->au.a_md5.md5_auth_len, 73546303Smarkm (int)ntohl(na->au.a_md5.md5_seqno), 73619880Swollman na->au.a_md5.rsvd[0], 73719880Swollman na->au.a_md5.rsvd[1]); 73846303Smarkm md5_authed = 1; 73919880Swollman continue; 74019880Swollman } 74119880Swollman (void)printf(" Authentication type %d: ", 74219880Swollman ntohs(na->a_type)); 74346303Smarkm for (i = 0; i < (int)sizeof(na->au.au_pw); i++) 74419880Swollman (void)printf("%02x ", na->au.au_pw[i]); 74518316Swollman putc('\n', stdout); 74646303Smarkm if (md5_authed && n+1 > lim 74746303Smarkm && na->a_type == ntohs(1)) { 74846303Smarkm MD5Init(&md5_ctx); 74946303Smarkm MD5Update(&md5_ctx, (u_char *)&IMSG, 750126250Sbms (char *)na-(char *)&IMSG 751126250Sbms +RIP_AUTH_MD5_HASH_XTRA); 75246303Smarkm MD5Update(&md5_ctx, (u_char *)passwd, 753126250Sbms RIP_AUTH_MD5_KEY_LEN); 75446303Smarkm MD5Final(hash, &md5_ctx); 75546303Smarkm (void)printf(" %s hash\n", 75646303Smarkm memcmp(hash, na->au.au_pw, 75746303Smarkm sizeof(hash)) 75846303Smarkm ? "WRONG" : "correct"); 75946303Smarkm } 76018316Swollman continue; 76118316Swollman 76218316Swollman } else { 76318316Swollman (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 76418316Swollman ntohs(n->n_family), 765126250Sbms (u_char)(n->n_dst >> 24), 766126250Sbms (u_char)(n->n_dst >> 16), 767126250Sbms (u_char)(n->n_dst >> 8), 768126250Sbms (u_char)n->n_dst); 76918316Swollman } 77018316Swollman 77118316Swollman (void)printf(" %-18s metric %2d %-10s", 77246303Smarkm net_buf, (int)ntohl(n->n_metric), name); 77318316Swollman 77418316Swollman if (n->n_nhop != 0) { 77518316Swollman in.s_addr = n->n_nhop; 77618316Swollman if (nflag) 77718316Swollman hp = 0; 77818316Swollman else 77918316Swollman hp = gethostbyaddr((char*)&in, sizeof(in), 78018316Swollman AF_INET); 78118316Swollman (void)printf(" nhop=%-15s%s", 78218316Swollman (hp != 0) ? hp->h_name : inet_ntoa(in), 78318316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 78418316Swollman } 78518316Swollman if (n->n_tag != 0) 78618316Swollman (void)printf(" tag=%#x%s", n->n_tag, 78718316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 78818316Swollman putc('\n', stdout); 78918316Swollman } 79018316Swollman} 79118316Swollman 79218316Swollman 79318316Swollman/* Return the classical netmask for an IP address. 79418316Swollman */ 79518316Swollmanstatic u_int 79618316Swollmanstd_mask(u_int addr) /* in network order */ 79718316Swollman{ 79890868Smike addr = ntohl(addr); /* was a host, not a network */ 79918316Swollman 80018316Swollman if (addr == 0) /* default route has mask 0 */ 80118316Swollman return 0; 80218316Swollman if (IN_CLASSA(addr)) 80318316Swollman return IN_CLASSA_NET; 80418316Swollman if (IN_CLASSB(addr)) 80518316Swollman return IN_CLASSB_NET; 80618316Swollman return IN_CLASSC_NET; 80718316Swollman} 80818316Swollman 80918316Swollman 81018316Swollman/* get a network number as a name or a number, with an optional "/xx" 81118316Swollman * netmask. 81218316Swollman */ 81318316Swollmanstatic int /* 0=bad */ 81418316Swollmangetnet(char *name, 81518316Swollman struct netinfo *rt) 81618316Swollman{ 81718316Swollman int i; 81818316Swollman struct netent *nentp; 81918316Swollman u_int mask; 82018316Swollman struct in_addr in; 82118316Swollman char hname[MAXHOSTNAMELEN+1]; 82218316Swollman char *mname, *p; 82318316Swollman 82418316Swollman 82518316Swollman /* Detect and separate "1.2.3.4/24" 82618316Swollman */ 82746303Smarkm if (0 != (mname = strrchr(name,'/'))) { 82818316Swollman i = (int)(mname - name); 82946303Smarkm if (i > (int)sizeof(hname)-1) /* name too long */ 83018316Swollman return 0; 83146303Smarkm memmove(hname, name, i); 83218316Swollman hname[i] = '\0'; 83318316Swollman mname++; 83418316Swollman name = hname; 83518316Swollman } 83618316Swollman 83718316Swollman nentp = getnetbyname(name); 83818316Swollman if (nentp != 0) { 83918316Swollman in.s_addr = nentp->n_net; 84018316Swollman } else if (inet_aton(name, &in) == 1) { 84190868Smike in.s_addr = ntohl(in.s_addr); 84218316Swollman } else { 84318316Swollman return 0; 84418316Swollman } 84518316Swollman 84618316Swollman if (mname == 0) { 84718316Swollman mask = std_mask(in.s_addr); 84818316Swollman if ((~mask & in.s_addr) != 0) 84918316Swollman mask = 0xffffffff; 85018316Swollman } else { 85118316Swollman mask = (u_int)strtoul(mname, &p, 0); 85218316Swollman if (*p != '\0' || mask > 32) 85318316Swollman return 0; 85418316Swollman mask = 0xffffffff << (32-mask); 85518316Swollman } 85618316Swollman 85718316Swollman rt->n_dst = htonl(in.s_addr); 85818316Swollman rt->n_family = RIP_AF_INET; 85918316Swollman rt->n_mask = htonl(mask); 86018316Swollman return 1; 86118316Swollman} 86219880Swollman 86319880Swollman 86419880Swollman/* strtok(), but honoring backslash 86519880Swollman */ 86619880Swollmanstatic int /* -1=bad */ 86719880Swollmanparse_quote(char **linep, 86846303Smarkm const char *delims, 86919880Swollman char *delimp, 87019880Swollman char *buf, 87119880Swollman int lim) 87219880Swollman{ 87346303Smarkm char c, *pc; 87446303Smarkm const char *p; 87519880Swollman 87619880Swollman 87719880Swollman pc = *linep; 87819880Swollman if (*pc == '\0') 87919880Swollman return -1; 88019880Swollman 88119880Swollman for (;;) { 88219880Swollman if (lim == 0) 88319880Swollman return -1; 88419880Swollman c = *pc++; 88519880Swollman if (c == '\0') 88619880Swollman break; 88719880Swollman 88837815Sphk if (c == '\\' && *pc != '\0') { 88919880Swollman if ((c = *pc++) == 'n') { 89019880Swollman c = '\n'; 89119880Swollman } else if (c == 'r') { 89219880Swollman c = '\r'; 89319880Swollman } else if (c == 't') { 89419880Swollman c = '\t'; 89519880Swollman } else if (c == 'b') { 89619880Swollman c = '\b'; 89719880Swollman } else if (c >= '0' && c <= '7') { 89819880Swollman c -= '0'; 89919880Swollman if (*pc >= '0' && *pc <= '7') { 90019880Swollman c = (c<<3)+(*pc++ - '0'); 90119880Swollman if (*pc >= '0' && *pc <= '7') 90219880Swollman c = (c<<3)+(*pc++ - '0'); 90319880Swollman } 90419880Swollman } 90519880Swollman 90619880Swollman } else { 90719880Swollman for (p = delims; *p != '\0'; ++p) { 90819880Swollman if (*p == c) 90919880Swollman goto exit; 91019880Swollman } 91119880Swollman } 91219880Swollman 91319880Swollman *buf++ = c; 91419880Swollman --lim; 91519880Swollman } 91619880Swollmanexit: 91719880Swollman if (delimp != 0) 91819880Swollman *delimp = c; 91919880Swollman *linep = pc-1; 92019880Swollman if (lim != 0) 92119880Swollman *buf = '\0'; 92219880Swollman return 0; 92319880Swollman} 924