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 * 4. Neither the name of the University nor the names of its contributors 1418316Swollman * may be used to endorse or promote products derived from this software 1518316Swollman * without specific prior written permission. 1618316Swollman * 1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2018316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2718316Swollman * SUCH DAMAGE. 2846303Smarkm * 2950476Speter * $FreeBSD: releng/11.0/sbin/routed/rtquery/rtquery.c 299768 2016-05-14 22:40:08Z pfg $ 3018316Swollman */ 3118316Swollman 3246303Smarkm#include <sys/cdefs.h> 3318316Swollman#include <sys/param.h> 3446303Smarkm#include <sys/protosw.h> 3518316Swollman#include <sys/socket.h> 3618316Swollman#include <sys/time.h> 3718316Swollman#include <netinet/in.h> 3818316Swollman#define RIPVERSION RIPv2 3918316Swollman#include <protocols/routed.h> 4018316Swollman#include <arpa/inet.h> 4146303Smarkm#include <netdb.h> 4232502Scharnier#include <errno.h> 4346303Smarkm#include <unistd.h> 4418316Swollman#include <stdio.h> 4518316Swollman#include <stdlib.h> 4618316Swollman#include <string.h> 4718316Swollman#ifdef sgi 4818316Swollman#include <strings.h> 4918316Swollman#include <bstring.h> 5018316Swollman#endif 5118316Swollman 52126250Sbms#define UNUSED __attribute__((unused)) 53126250Sbms#ifndef __RCSID 54126250Sbms#define __RCSID(_s) static const char rcsid[] UNUSED = _s 5546303Smarkm#endif 56126250Sbms#ifndef __COPYRIGHT 57126250Sbms#define __COPYRIGHT(_s) static const char copyright[] UNUSED = _s 58126250Sbms#endif 59126250Sbms__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n" 60126250Sbms "The Regents of the University of California." 61126250Sbms " All rights reserved.\n"); 62126250Sbms#ifdef __NetBSD__ 63126250Sbms__RCSID("$NetBSD$"); 64126250Sbms#elif defined(__FreeBSD__) 65126250Sbms__RCSID("$FreeBSD: releng/11.0/sbin/routed/rtquery/rtquery.c 299768 2016-05-14 22:40:08Z pfg $"); 66126250Sbms#else 67126250Sbms__RCSID("$Revision: 2.26 $"); 68126250Sbms#ident "$Revision: 2.26 $" 69126250Sbms#endif 7046303Smarkm 7118316Swollman#ifndef sgi 7218316Swollman#define _HAVE_SIN_LEN 7318316Swollman#endif 7418316Swollman 75126250Sbms#ifdef __NetBSD__ 76126250Sbms#include <md5.h> 77126250Sbms#else 7846303Smarkm#define MD5_DIGEST_LEN 16 7946303Smarkmtypedef struct { 8046303Smarkm u_int32_t state[4]; /* state (ABCD) */ 8146303Smarkm u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ 8246303Smarkm unsigned char buffer[64]; /* input buffer */ 8346303Smarkm} MD5_CTX; 8446303Smarkmextern void MD5Init(MD5_CTX*); 8546303Smarkmextern void MD5Update(MD5_CTX*, u_char*, u_int); 8646303Smarkmextern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); 87126250Sbms#endif 8846303Smarkm 8946303Smarkm 9018316Swollman#define WTIME 15 /* Time to wait for all responses */ 9118316Swollman#define STIME (250*1000) /* usec to wait for another response */ 9218316Swollman 9346303Smarkmint soc; 9418316Swollman 9546303Smarkmconst char *pgmname; 9646303Smarkm 9718316Swollmanunion { 9818316Swollman struct rip rip; 9918316Swollman char packet[MAXPACKETSIZE+MAXPATHLEN]; 10018316Swollman} omsg_buf; 10118316Swollman#define OMSG omsg_buf.rip 10218316Swollmanint omsg_len = sizeof(struct rip); 10318316Swollman 10418316Swollmanunion { 10518316Swollman struct rip rip; 10618316Swollman char packet[MAXPACKETSIZE+1024]; 10718316Swollman } imsg_buf; 10818316Swollman#define IMSG imsg_buf.rip 10918316Swollman 11018316Swollmanint nflag; /* numbers, no names */ 11118316Swollmanint pflag; /* play the `gated` game */ 11218316Swollmanint ripv2 = 1; /* use RIP version 2 */ 11318316Swollmanint wtime = WTIME; 11418316Swollmanint rflag; /* 1=ask about a particular route */ 11519880Swollmanint trace, not_trace; /* send trace command or not */ 11619880Swollmanint auth_type = RIP_AUTH_NONE; 11719880Swollmanchar passwd[RIP_AUTH_PW_LEN]; 11819880Swollmanu_long keyid; 11918316Swollman 12018316Swollmanstruct timeval sent; /* when query sent */ 12118316Swollman 12246303Smarkmstatic char localhost_str[] = "localhost"; 12346303Smarkmstatic char *default_argv[] = {localhost_str, 0}; 12446303Smarkm 12518316Swollmanstatic void rip_input(struct sockaddr_in*, int); 12646303Smarkmstatic int out(const char *); 12746303Smarkmstatic void trace_loop(char *argv[]) __attribute((__noreturn__)); 12846303Smarkmstatic void query_loop(char *argv[], int) __attribute((__noreturn__)); 12918316Swollmanstatic int getnet(char *, struct netinfo *); 13018316Swollmanstatic u_int std_mask(u_int); 13146303Smarkmstatic int parse_quote(char **, const char *, char *, char *, int); 13237908Scharnierstatic void usage(void); 13318316Swollman 13446303Smarkm 13537908Scharnierint 13618316Swollmanmain(int argc, 13718316Swollman char *argv[]) 13818316Swollman{ 13918316Swollman int ch, bsize; 14019880Swollman char *p, *options, *value, delim; 14146303Smarkm const char *result; 14218316Swollman 14318316Swollman OMSG.rip_nets[0].n_dst = RIP_DEFAULT; 14418316Swollman OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; 14518316Swollman OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 14618316Swollman 14746303Smarkm pgmname = argv[0]; 14824359Simp while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) 14918316Swollman switch (ch) { 15018316Swollman case 'n': 15118316Swollman not_trace = 1; 15218316Swollman nflag = 1; 15318316Swollman break; 15418316Swollman 15518316Swollman case 'p': 15618316Swollman not_trace = 1; 15718316Swollman pflag = 1; 15818316Swollman break; 15918316Swollman 16018316Swollman case '1': 16118316Swollman ripv2 = 0; 16218316Swollman break; 16318316Swollman 16418316Swollman case 'w': 16518316Swollman not_trace = 1; 16618316Swollman wtime = (int)strtoul(optarg, &p, 0); 16718316Swollman if (*p != '\0' 16818316Swollman || wtime <= 0) 16937908Scharnier usage(); 17018316Swollman break; 17118316Swollman 17218316Swollman case 'r': 17318316Swollman not_trace = 1; 17418316Swollman if (rflag) 17537908Scharnier usage(); 17618316Swollman rflag = getnet(optarg, &OMSG.rip_nets[0]); 17718316Swollman if (!rflag) { 17818316Swollman struct hostent *hp = gethostbyname(optarg); 179299768Spfg if (hp == NULL) { 18046303Smarkm fprintf(stderr, "%s: %s:", 18146303Smarkm pgmname, optarg); 18246303Smarkm herror(0); 18346303Smarkm exit(1); 18446303Smarkm } 18546303Smarkm memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr, 18646303Smarkm sizeof(OMSG.rip_nets[0].n_dst)); 18718316Swollman OMSG.rip_nets[0].n_family = RIP_AF_INET; 18818316Swollman OMSG.rip_nets[0].n_mask = -1; 18918316Swollman rflag = 1; 19018316Swollman } 19118316Swollman break; 19218316Swollman 19318316Swollman case 't': 19418316Swollman trace = 1; 19518316Swollman options = optarg; 19618316Swollman while (*options != '\0') { 19746303Smarkm /* messy complications to make -W -Wall happy */ 19846303Smarkm static char on_str[] = "on"; 19946303Smarkm static char more_str[] = "more"; 20046303Smarkm static char off_str[] = "off"; 20146303Smarkm static char dump_str[] = "dump"; 20246303Smarkm static char *traceopts[] = { 20318316Swollman# define TRACE_ON 0 20446303Smarkm on_str, 20518316Swollman# define TRACE_MORE 1 20646303Smarkm more_str, 20718316Swollman# define TRACE_OFF 2 20846303Smarkm off_str, 20918316Swollman# define TRACE_DUMP 3 21046303Smarkm dump_str, 21118316Swollman 0 21218316Swollman }; 21346303Smarkm result = ""; 21418316Swollman switch (getsubopt(&options,traceopts,&value)) { 21518316Swollman case TRACE_ON: 21618316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 21718316Swollman if (!value 21818316Swollman || strlen(value) > MAXPATHLEN) 21946303Smarkm usage(); 22046303Smarkm result = value; 22118316Swollman break; 22218316Swollman case TRACE_MORE: 22318316Swollman if (value) 22446303Smarkm usage(); 22518316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 22618316Swollman break; 22718316Swollman case TRACE_OFF: 22818316Swollman if (value) 22946303Smarkm usage(); 23018316Swollman OMSG.rip_cmd = RIPCMD_TRACEOFF; 23118316Swollman break; 23218316Swollman case TRACE_DUMP: 23318316Swollman if (value) 23446303Smarkm usage(); 23518316Swollman OMSG.rip_cmd = RIPCMD_TRACEON; 23646303Smarkm result = "dump/../table"; 23718316Swollman break; 23818316Swollman default: 23937908Scharnier usage(); 24018316Swollman } 24146303Smarkm strcpy((char*)OMSG.rip_tracefile, result); 24246303Smarkm omsg_len += strlen(result) - sizeof(OMSG.ripun); 24318316Swollman } 24418316Swollman break; 24518316Swollman 24619880Swollman case 'a': 24719880Swollman not_trace = 1; 24819880Swollman p = strchr(optarg,'='); 24919880Swollman if (!p) 25037908Scharnier usage(); 25119880Swollman *p++ = '\0'; 25219880Swollman if (!strcasecmp("passwd",optarg)) 25319880Swollman auth_type = RIP_AUTH_PW; 25419880Swollman else if (!strcasecmp("md5_passwd",optarg)) 25519880Swollman auth_type = RIP_AUTH_MD5; 25619880Swollman else 25737908Scharnier usage(); 25819880Swollman if (0 > parse_quote(&p,"|",&delim, 25946303Smarkm passwd, sizeof(passwd))) 26037908Scharnier usage(); 26119880Swollman if (auth_type == RIP_AUTH_MD5 26219880Swollman && delim == '|') { 26319880Swollman keyid = strtoul(p+1,&p,0); 26419880Swollman if (keyid > 255 || *p != '\0') 26537908Scharnier usage(); 26619880Swollman } else if (delim != '\0') { 26737908Scharnier usage(); 26819880Swollman } 26919880Swollman break; 27019880Swollman 27118316Swollman default: 27237908Scharnier usage(); 27318316Swollman } 27418316Swollman argv += optind; 27518316Swollman argc -= optind; 27646303Smarkm if (not_trace && trace) 27737908Scharnier usage(); 27846303Smarkm if (argc == 0) { 27946303Smarkm argc = 1; 28046303Smarkm argv = default_argv; 28146303Smarkm } 28218316Swollman 28346303Smarkm soc = socket(AF_INET, SOCK_DGRAM, 0); 28446303Smarkm if (soc < 0) { 28546524Smarkm perror("socket"); 28646524Smarkm exit(2); 28746303Smarkm } 28818316Swollman 28918316Swollman /* be prepared to receive a lot of routes */ 29018316Swollman for (bsize = 127*1024; ; bsize -= 1024) { 29146303Smarkm if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF, 29218316Swollman &bsize, sizeof(bsize)) == 0) 29318316Swollman break; 29418316Swollman if (bsize <= 4*1024) { 29546524Smarkm perror("setsockopt SO_RCVBUF"); 29618316Swollman break; 29718316Swollman } 29818316Swollman } 29918316Swollman 30018316Swollman if (trace) 30118316Swollman trace_loop(argv); 30218316Swollman else 30318316Swollman query_loop(argv, argc); 30418316Swollman /* NOTREACHED */ 30546303Smarkm return 0; 30618316Swollman} 30718316Swollman 30846303Smarkm 30937908Scharnierstatic void 31046303Smarkmusage(void) 31137908Scharnier{ 31246303Smarkm fprintf(stderr, 31346303Smarkm "usage: rtquery [-np1] [-r tgt_rt] [-w wtime]" 31446303Smarkm " [-a type=passwd] host1 [host2 ...]\n" 31546303Smarkm "\trtquery -t {on=filename|more|off|dump}" 31646303Smarkm " host1 [host2 ...]\n"); 31737908Scharnier exit(1); 31837908Scharnier} 31918316Swollman 32046303Smarkm 32118316Swollman/* tell the target hosts about tracing 32218316Swollman */ 32318316Swollmanstatic void 32418316Swollmantrace_loop(char *argv[]) 32518316Swollman{ 32618316Swollman struct sockaddr_in myaddr; 32718316Swollman int res; 32818316Swollman 32946303Smarkm if (geteuid() != 0) { 33046303Smarkm (void)fprintf(stderr, "-t requires UID 0\n"); 33146303Smarkm exit(1); 33246303Smarkm } 33318316Swollman 33418316Swollman if (ripv2) { 33518316Swollman OMSG.rip_vers = RIPv2; 33618316Swollman } else { 33718316Swollman OMSG.rip_vers = RIPv1; 33818316Swollman } 33918316Swollman 34046303Smarkm memset(&myaddr, 0, sizeof(myaddr)); 34118316Swollman myaddr.sin_family = AF_INET; 34218316Swollman#ifdef _HAVE_SIN_LEN 34318316Swollman myaddr.sin_len = sizeof(myaddr); 34418316Swollman#endif 34518316Swollman myaddr.sin_port = htons(IPPORT_RESERVED-1); 34646303Smarkm while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 34746303Smarkm if (errno != EADDRINUSE 34846303Smarkm || myaddr.sin_port == 0) { 34946524Smarkm perror("bind"); 35046524Smarkm exit(2); 35146303Smarkm } 35218316Swollman myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); 35318316Swollman } 35418316Swollman 35518316Swollman res = 1; 356299768Spfg while (*argv != NULL) { 35718316Swollman if (out(*argv++) <= 0) 35818316Swollman res = 0; 35918316Swollman } 36018316Swollman exit(res); 36118316Swollman} 36218316Swollman 36318316Swollman 36418316Swollman/* query all of the listed hosts 36518316Swollman */ 36618316Swollmanstatic void 36718316Swollmanquery_loop(char *argv[], int argc) 36818316Swollman{ 36919880Swollman# define NA0 (OMSG.rip_auths[0]) 37019880Swollman# define NA2 (OMSG.rip_auths[2]) 37118316Swollman struct seen { 37218316Swollman struct seen *next; 37318316Swollman struct in_addr addr; 37418316Swollman } *seen, *sp; 37518316Swollman int answered = 0; 37618316Swollman int cc; 37718316Swollman fd_set bits; 37818316Swollman struct timeval now, delay; 37918316Swollman struct sockaddr_in from; 38018316Swollman int fromlen; 38119880Swollman MD5_CTX md5_ctx; 38218316Swollman 38318316Swollman 38418316Swollman OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; 38518316Swollman if (ripv2) { 38618316Swollman OMSG.rip_vers = RIPv2; 38719880Swollman if (auth_type == RIP_AUTH_PW) { 38819880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 38919880Swollman NA0.a_family = RIP_AF_AUTH; 39019880Swollman NA0.a_type = RIP_AUTH_PW; 39146303Smarkm memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN); 39219880Swollman omsg_len += sizeof(OMSG.rip_nets[0]); 39319880Swollman 39419880Swollman } else if (auth_type == RIP_AUTH_MD5) { 39519880Swollman OMSG.rip_nets[1] = OMSG.rip_nets[0]; 39619880Swollman NA0.a_family = RIP_AF_AUTH; 39719880Swollman NA0.a_type = RIP_AUTH_MD5; 39819880Swollman NA0.au.a_md5.md5_keyid = (int8_t)keyid; 399126250Sbms NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_KEY_LEN; 40019880Swollman NA0.au.a_md5.md5_seqno = 0; 40146303Smarkm cc = (char *)&NA2-(char *)&OMSG; 40246303Smarkm NA0.au.a_md5.md5_pkt_len = htons(cc); 40319880Swollman NA2.a_family = RIP_AF_AUTH; 40446303Smarkm NA2.a_type = htons(1); 40519880Swollman MD5Init(&md5_ctx); 40646303Smarkm MD5Update(&md5_ctx, 40746303Smarkm (u_char *)&OMSG, cc); 40846303Smarkm MD5Update(&md5_ctx, 409126250Sbms (u_char *)passwd, RIP_AUTH_MD5_HASH_LEN); 41019880Swollman MD5Final(NA2.au.au_pw, &md5_ctx); 41119880Swollman omsg_len += 2*sizeof(OMSG.rip_nets[0]); 41219880Swollman } 41319880Swollman 41418316Swollman } else { 41518316Swollman OMSG.rip_vers = RIPv1; 41618316Swollman OMSG.rip_nets[0].n_mask = 0; 41718316Swollman } 41818316Swollman 41918316Swollman /* ask the first (valid) host */ 420299768Spfg seen = NULL; 42118316Swollman while (0 > out(*argv++)) { 422299768Spfg if (*argv == NULL) 423126250Sbms exit(1); 42418316Swollman answered++; 42518316Swollman } 42618316Swollman 42718316Swollman FD_ZERO(&bits); 42818316Swollman for (;;) { 42946303Smarkm FD_SET(soc, &bits); 43018316Swollman delay.tv_sec = 0; 43118316Swollman delay.tv_usec = STIME; 43246303Smarkm cc = select(soc+1, &bits, 0,0, &delay); 43318316Swollman if (cc > 0) { 43418316Swollman fromlen = sizeof(from); 43546303Smarkm cc = recvfrom(soc, imsg_buf.packet, 43618316Swollman sizeof(imsg_buf.packet), 0, 43718316Swollman (struct sockaddr *)&from, &fromlen); 43846303Smarkm if (cc < 0) { 43946524Smarkm perror("recvfrom"); 44046524Smarkm exit(1); 44146303Smarkm } 44218316Swollman /* count the distinct responding hosts. 44318316Swollman * You cannot match responding hosts with 44418316Swollman * addresses to which queries were transmitted, 44518316Swollman * because a router might respond with a 44618316Swollman * different source address. 44718316Swollman */ 448299768Spfg for (sp = seen; sp != NULL; sp = sp->next) { 44918316Swollman if (sp->addr.s_addr == from.sin_addr.s_addr) 45018316Swollman break; 45118316Swollman } 452299768Spfg if (sp == NULL) { 45318316Swollman sp = malloc(sizeof(*sp)); 454299768Spfg if (sp == NULL) { 45546303Smarkm fprintf(stderr, 45646303Smarkm "rtquery: malloc failed\n"); 45746303Smarkm exit(1); 45846303Smarkm } 45918316Swollman sp->addr = from.sin_addr; 46018316Swollman sp->next = seen; 46118316Swollman seen = sp; 46218316Swollman answered++; 46318316Swollman } 46418316Swollman 46518316Swollman rip_input(&from, cc); 46618316Swollman continue; 46718316Swollman } 46818316Swollman 46918316Swollman if (cc < 0) { 47032502Scharnier if (errno == EINTR) 47118316Swollman continue; 47246524Smarkm perror("select"); 47346524Smarkm exit(1); 47418316Swollman } 47518316Swollman 47618316Swollman /* After a pause in responses, probe another host. 47718316Swollman * This reduces the intermingling of answers. 47818316Swollman */ 479299768Spfg while (*argv != NULL && out(*argv++) < 0) 48018316Swollman answered++; 48118316Swollman 48218316Swollman /* continue until no more packets arrive 48318316Swollman * or we have heard from all hosts 48418316Swollman */ 48518316Swollman if (answered >= argc) 48618316Swollman break; 48718316Swollman 48818316Swollman /* or until we have waited a long time 48918316Swollman */ 49046303Smarkm if (gettimeofday(&now, 0) < 0) { 49146524Smarkm perror("gettimeofday(now)"); 49246524Smarkm exit(1); 49346303Smarkm } 49418316Swollman if (sent.tv_sec + wtime <= now.tv_sec) 49518316Swollman break; 49618316Swollman } 49718316Swollman 49818316Swollman /* fail if there was no answer */ 49918316Swollman exit (answered >= argc ? 0 : 1); 50018316Swollman} 50118316Swollman 50218316Swollman 50319880Swollman/* send to one host 50418316Swollman */ 50518316Swollmanstatic int 50646303Smarkmout(const char *host) 50718316Swollman{ 50818316Swollman struct sockaddr_in router; 50918316Swollman struct hostent *hp; 51018316Swollman 51118316Swollman if (gettimeofday(&sent, 0) < 0) { 51246524Smarkm perror("gettimeofday(sent)"); 51346524Smarkm return -1; 51418316Swollman } 51518316Swollman 51646303Smarkm memset(&router, 0, sizeof(router)); 51718316Swollman router.sin_family = AF_INET; 51818316Swollman#ifdef _HAVE_SIN_LEN 51918316Swollman router.sin_len = sizeof(router); 52018316Swollman#endif 52118316Swollman if (!inet_aton(host, &router.sin_addr)) { 52218316Swollman hp = gethostbyname(host); 523299768Spfg if (hp == NULL) { 52418316Swollman herror(host); 52518316Swollman return -1; 52618316Swollman } 52746303Smarkm memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr)); 52818316Swollman } 52918316Swollman router.sin_port = htons(RIP_PORT); 53018316Swollman 53146303Smarkm if (sendto(soc, &omsg_buf, omsg_len, 0, 53218316Swollman (struct sockaddr *)&router, sizeof(router)) < 0) { 53346524Smarkm perror(host); 53446524Smarkm return -1; 53518316Swollman } 53618316Swollman 53718316Swollman return 0; 53818316Swollman} 53918316Swollman 54018316Swollman 54118316Swollman/* 54219880Swollman * Convert string to printable characters 54319880Swollman */ 54419880Swollmanstatic char * 54519880Swollmanqstring(u_char *s, int len) 54619880Swollman{ 54719880Swollman static char buf[8*20+1]; 54819880Swollman char *p; 54919880Swollman u_char *s2, c; 55019880Swollman 55119880Swollman 55219880Swollman for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) { 55319880Swollman c = *s++; 55419880Swollman if (c == '\0') { 55519880Swollman for (s2 = s+1; s2 < &s[len]; s2++) { 55619880Swollman if (*s2 != '\0') 55719880Swollman break; 55819880Swollman } 55919880Swollman if (s2 >= &s[len]) 56019880Swollman goto exit; 56119880Swollman } 56219880Swollman 56319880Swollman if (c >= ' ' && c < 0x7f && c != '\\') { 56419880Swollman *p++ = c; 56519880Swollman continue; 56619880Swollman } 56719880Swollman *p++ = '\\'; 56819880Swollman switch (c) { 56919880Swollman case '\\': 57019880Swollman *p++ = '\\'; 57119880Swollman break; 57219880Swollman case '\n': 57319880Swollman *p++= 'n'; 57419880Swollman break; 57519880Swollman case '\r': 57619880Swollman *p++= 'r'; 57719880Swollman break; 57819880Swollman case '\t': 57919880Swollman *p++ = 't'; 58019880Swollman break; 58119880Swollman case '\b': 58219880Swollman *p++ = 'b'; 58319880Swollman break; 58419880Swollman default: 58519880Swollman p += sprintf(p,"%o",c); 58619880Swollman break; 58719880Swollman } 58819880Swollman } 58919880Swollmanexit: 59019880Swollman *p = '\0'; 59119880Swollman return buf; 59219880Swollman} 59319880Swollman 59419880Swollman 59519880Swollman/* 59618316Swollman * Handle an incoming RIP packet. 59718316Swollman */ 59818316Swollmanstatic void 59918316Swollmanrip_input(struct sockaddr_in *from, 60018316Swollman int size) 60118316Swollman{ 60218316Swollman struct netinfo *n, *lim; 60318316Swollman struct in_addr in; 60446303Smarkm const char *name; 60518316Swollman char net_buf[80]; 606126250Sbms u_char hash[RIP_AUTH_MD5_KEY_LEN]; 60746303Smarkm MD5_CTX md5_ctx; 60846303Smarkm u_char md5_authed = 0; 60918316Swollman u_int mask, dmask; 61018316Swollman char *sp; 61118316Swollman int i; 61218316Swollman struct hostent *hp; 61318316Swollman struct netent *np; 61419880Swollman struct netauth *na; 61518316Swollman 61618316Swollman 61718316Swollman if (nflag) { 61818316Swollman printf("%s:", inet_ntoa(from->sin_addr)); 61918316Swollman } else { 62018316Swollman hp = gethostbyaddr((char*)&from->sin_addr, 62118316Swollman sizeof(struct in_addr), AF_INET); 622299768Spfg if (hp == NULL) { 62318316Swollman printf("%s:", 62418316Swollman inet_ntoa(from->sin_addr)); 62518316Swollman } else { 62618316Swollman printf("%s (%s):", hp->h_name, 62718316Swollman inet_ntoa(from->sin_addr)); 62818316Swollman } 62918316Swollman } 63018316Swollman if (IMSG.rip_cmd != RIPCMD_RESPONSE) { 63118316Swollman printf("\n unexpected response type %d\n", IMSG.rip_cmd); 63218316Swollman return; 63318316Swollman } 63418316Swollman printf(" RIPv%d%s %d bytes\n", IMSG.rip_vers, 63518316Swollman (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", 63618316Swollman size); 63718316Swollman if (size > MAXPACKETSIZE) { 63846303Smarkm if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) { 63918316Swollman printf(" at least %d bytes too long\n", 64018316Swollman size-MAXPACKETSIZE); 64146303Smarkm size = (int)sizeof(imsg_buf) - (int)sizeof(*n); 64218316Swollman } else { 64318316Swollman printf(" %d bytes too long\n", 64418316Swollman size-MAXPACKETSIZE); 64518316Swollman } 64618316Swollman } else if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { 64718316Swollman printf(" response of bad length=%d\n", size); 64818316Swollman } 64918316Swollman 65018316Swollman n = IMSG.rip_nets; 65118316Swollman lim = (struct netinfo *)((char*)n + size) - 1; 65218316Swollman for (; n <= lim; n++) { 65318316Swollman name = ""; 65418316Swollman if (n->n_family == RIP_AF_INET) { 65518316Swollman in.s_addr = n->n_dst; 65618316Swollman (void)strcpy(net_buf, inet_ntoa(in)); 65718316Swollman 65818316Swollman mask = ntohl(n->n_mask); 65918316Swollman dmask = mask & -mask; 66018316Swollman if (mask != 0) { 66118316Swollman sp = &net_buf[strlen(net_buf)]; 66218316Swollman if (IMSG.rip_vers == RIPv1) { 66318316Swollman (void)sprintf(sp," mask=%#x ? ",mask); 66418316Swollman mask = 0; 66518316Swollman } else if (mask + dmask == 0) { 66618316Swollman for (i = 0; 66718316Swollman (i != 32 66818316Swollman && ((1<<i)&mask) == 0); 66918316Swollman i++) 67018316Swollman continue; 67118316Swollman (void)sprintf(sp, "/%d",32-i); 67218316Swollman } else { 67318316Swollman (void)sprintf(sp," (mask %#x)", mask); 67418316Swollman } 67518316Swollman } 67618316Swollman 67718316Swollman if (!nflag) { 67818316Swollman if (mask == 0) { 67918316Swollman mask = std_mask(in.s_addr); 68018316Swollman if ((ntohl(in.s_addr) & ~mask) != 0) 68118316Swollman mask = 0; 68218316Swollman } 68318316Swollman /* Without a netmask, do not worry about 68418316Swollman * whether the destination is a host or a 68518316Swollman * network. Try both and use the first name 68618316Swollman * we get. 68718316Swollman * 68818316Swollman * If we have a netmask we can make a 68918316Swollman * good guess. 69018316Swollman */ 69118316Swollman if ((in.s_addr & ~mask) == 0) { 69218316Swollman np = getnetbyaddr((long)in.s_addr, 69318316Swollman AF_INET); 694299768Spfg if (np != NULL) 69518316Swollman name = np->n_name; 69618316Swollman else if (in.s_addr == 0) 69718316Swollman name = "default"; 69818316Swollman } 69918316Swollman if (name[0] == '\0' 70018316Swollman && ((in.s_addr & ~mask) != 0 70118316Swollman || mask == 0xffffffff)) { 70218316Swollman hp = gethostbyaddr((char*)&in, 70318316Swollman sizeof(in), 70418316Swollman AF_INET); 705299768Spfg if (hp != NULL) 70618316Swollman name = hp->h_name; 70718316Swollman } 70818316Swollman } 70918316Swollman 71018316Swollman } else if (n->n_family == RIP_AF_AUTH) { 71119880Swollman na = (struct netauth*)n; 71219880Swollman if (na->a_type == RIP_AUTH_PW 71319880Swollman && n == IMSG.rip_nets) { 71419880Swollman (void)printf(" Password Authentication:" 71519880Swollman " \"%s\"\n", 71619880Swollman qstring(na->au.au_pw, 71719880Swollman RIP_AUTH_PW_LEN)); 71819880Swollman continue; 71919880Swollman } 72019880Swollman 72119880Swollman if (na->a_type == RIP_AUTH_MD5 72219880Swollman && n == IMSG.rip_nets) { 72346303Smarkm (void)printf(" MD5 Auth" 72419880Swollman " len=%d KeyID=%d" 72546303Smarkm " auth_len=%d" 72646303Smarkm " seqno=%#x" 72719880Swollman " rsvd=%#x,%#x\n", 72846303Smarkm ntohs(na->au.a_md5.md5_pkt_len), 72919880Swollman na->au.a_md5.md5_keyid, 73046303Smarkm na->au.a_md5.md5_auth_len, 73146303Smarkm (int)ntohl(na->au.a_md5.md5_seqno), 73219880Swollman na->au.a_md5.rsvd[0], 73319880Swollman na->au.a_md5.rsvd[1]); 73446303Smarkm md5_authed = 1; 73519880Swollman continue; 73619880Swollman } 73719880Swollman (void)printf(" Authentication type %d: ", 73819880Swollman ntohs(na->a_type)); 73946303Smarkm for (i = 0; i < (int)sizeof(na->au.au_pw); i++) 74019880Swollman (void)printf("%02x ", na->au.au_pw[i]); 74118316Swollman putc('\n', stdout); 74246303Smarkm if (md5_authed && n+1 > lim 74346303Smarkm && na->a_type == ntohs(1)) { 74446303Smarkm MD5Init(&md5_ctx); 74546303Smarkm MD5Update(&md5_ctx, (u_char *)&IMSG, 746126250Sbms (char *)na-(char *)&IMSG 747126250Sbms +RIP_AUTH_MD5_HASH_XTRA); 74846303Smarkm MD5Update(&md5_ctx, (u_char *)passwd, 749126250Sbms RIP_AUTH_MD5_KEY_LEN); 75046303Smarkm MD5Final(hash, &md5_ctx); 75146303Smarkm (void)printf(" %s hash\n", 75246303Smarkm memcmp(hash, na->au.au_pw, 75346303Smarkm sizeof(hash)) 75446303Smarkm ? "WRONG" : "correct"); 75546303Smarkm } 75618316Swollman continue; 75718316Swollman 75818316Swollman } else { 75918316Swollman (void)sprintf(net_buf, "(af %#x) %d.%d.%d.%d", 76018316Swollman ntohs(n->n_family), 761126250Sbms (u_char)(n->n_dst >> 24), 762126250Sbms (u_char)(n->n_dst >> 16), 763126250Sbms (u_char)(n->n_dst >> 8), 764126250Sbms (u_char)n->n_dst); 76518316Swollman } 76618316Swollman 76718316Swollman (void)printf(" %-18s metric %2d %-10s", 76846303Smarkm net_buf, (int)ntohl(n->n_metric), name); 76918316Swollman 77018316Swollman if (n->n_nhop != 0) { 77118316Swollman in.s_addr = n->n_nhop; 77218316Swollman if (nflag) 773299768Spfg hp = NULL; 77418316Swollman else 77518316Swollman hp = gethostbyaddr((char*)&in, sizeof(in), 77618316Swollman AF_INET); 77718316Swollman (void)printf(" nhop=%-15s%s", 778299768Spfg (hp != NULL) ? hp->h_name : inet_ntoa(in), 77918316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 78018316Swollman } 78118316Swollman if (n->n_tag != 0) 78218316Swollman (void)printf(" tag=%#x%s", n->n_tag, 78318316Swollman (IMSG.rip_vers == RIPv1) ? " ?" : ""); 78418316Swollman putc('\n', stdout); 78518316Swollman } 78618316Swollman} 78718316Swollman 78818316Swollman 78918316Swollman/* Return the classical netmask for an IP address. 79018316Swollman */ 79118316Swollmanstatic u_int 79218316Swollmanstd_mask(u_int addr) /* in network order */ 79318316Swollman{ 79490868Smike addr = ntohl(addr); /* was a host, not a network */ 79518316Swollman 79618316Swollman if (addr == 0) /* default route has mask 0 */ 79718316Swollman return 0; 79818316Swollman if (IN_CLASSA(addr)) 79918316Swollman return IN_CLASSA_NET; 80018316Swollman if (IN_CLASSB(addr)) 80118316Swollman return IN_CLASSB_NET; 80218316Swollman return IN_CLASSC_NET; 80318316Swollman} 80418316Swollman 80518316Swollman 80618316Swollman/* get a network number as a name or a number, with an optional "/xx" 80718316Swollman * netmask. 80818316Swollman */ 80918316Swollmanstatic int /* 0=bad */ 81018316Swollmangetnet(char *name, 81118316Swollman struct netinfo *rt) 81218316Swollman{ 81318316Swollman int i; 81418316Swollman struct netent *nentp; 81518316Swollman u_int mask; 81618316Swollman struct in_addr in; 81718316Swollman char hname[MAXHOSTNAMELEN+1]; 81818316Swollman char *mname, *p; 81918316Swollman 82018316Swollman 82118316Swollman /* Detect and separate "1.2.3.4/24" 82218316Swollman */ 823299768Spfg if (NULL != (mname = strrchr(name,'/'))) { 82418316Swollman i = (int)(mname - name); 82546303Smarkm if (i > (int)sizeof(hname)-1) /* name too long */ 82618316Swollman return 0; 82746303Smarkm memmove(hname, name, i); 82818316Swollman hname[i] = '\0'; 82918316Swollman mname++; 83018316Swollman name = hname; 83118316Swollman } 83218316Swollman 83318316Swollman nentp = getnetbyname(name); 834299768Spfg if (nentp != NULL) { 83518316Swollman in.s_addr = nentp->n_net; 83618316Swollman } else if (inet_aton(name, &in) == 1) { 83790868Smike in.s_addr = ntohl(in.s_addr); 83818316Swollman } else { 83918316Swollman return 0; 84018316Swollman } 84118316Swollman 842299768Spfg if (mname == NULL) { 84318316Swollman mask = std_mask(in.s_addr); 84418316Swollman if ((~mask & in.s_addr) != 0) 84518316Swollman mask = 0xffffffff; 84618316Swollman } else { 84718316Swollman mask = (u_int)strtoul(mname, &p, 0); 84818316Swollman if (*p != '\0' || mask > 32) 84918316Swollman return 0; 85018316Swollman mask = 0xffffffff << (32-mask); 85118316Swollman } 85218316Swollman 85318316Swollman rt->n_dst = htonl(in.s_addr); 85418316Swollman rt->n_family = RIP_AF_INET; 85518316Swollman rt->n_mask = htonl(mask); 85618316Swollman return 1; 85718316Swollman} 85819880Swollman 85919880Swollman 86019880Swollman/* strtok(), but honoring backslash 86119880Swollman */ 86219880Swollmanstatic int /* -1=bad */ 86319880Swollmanparse_quote(char **linep, 86446303Smarkm const char *delims, 86519880Swollman char *delimp, 86619880Swollman char *buf, 86719880Swollman int lim) 86819880Swollman{ 86946303Smarkm char c, *pc; 87046303Smarkm const char *p; 87119880Swollman 87219880Swollman 87319880Swollman pc = *linep; 87419880Swollman if (*pc == '\0') 87519880Swollman return -1; 87619880Swollman 87719880Swollman for (;;) { 87819880Swollman if (lim == 0) 87919880Swollman return -1; 88019880Swollman c = *pc++; 88119880Swollman if (c == '\0') 88219880Swollman break; 88319880Swollman 88437815Sphk if (c == '\\' && *pc != '\0') { 88519880Swollman if ((c = *pc++) == 'n') { 88619880Swollman c = '\n'; 88719880Swollman } else if (c == 'r') { 88819880Swollman c = '\r'; 88919880Swollman } else if (c == 't') { 89019880Swollman c = '\t'; 89119880Swollman } else if (c == 'b') { 89219880Swollman c = '\b'; 89319880Swollman } else if (c >= '0' && c <= '7') { 89419880Swollman c -= '0'; 89519880Swollman if (*pc >= '0' && *pc <= '7') { 89619880Swollman c = (c<<3)+(*pc++ - '0'); 89719880Swollman if (*pc >= '0' && *pc <= '7') 89819880Swollman c = (c<<3)+(*pc++ - '0'); 89919880Swollman } 90019880Swollman } 90119880Swollman 90219880Swollman } else { 90319880Swollman for (p = delims; *p != '\0'; ++p) { 90419880Swollman if (*p == c) 90519880Swollman goto exit; 90619880Swollman } 90719880Swollman } 90819880Swollman 90919880Swollman *buf++ = c; 91019880Swollman --lim; 91119880Swollman } 91219880Swollmanexit: 913299768Spfg if (delimp != NULL) 91419880Swollman *delimp = c; 91519880Swollman *linep = pc-1; 91619880Swollman if (lim != 0) 91719880Swollman *buf = '\0'; 91819880Swollman return 0; 91919880Swollman} 920