/* * ripadv - advertise routes via RIP * * Usage: ripadv [-1] [-2] [-0] [-a] [-p] [-b] * src-address[/src-port] target-address[/target-port] * route-spec [route-spec ...] * * As its sole author, I explicitly place this file in the public * domain. It may be used by anyone in any way for any purpose, * though I would appreciate credit where it's due. * * der Mouse * * mouse@rodents.montreal.qc.ca * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B */ #include #include #include #include #include #include #include #include #include extern const char *__progname; typedef struct rt RT; struct rt { struct in_addr to; struct in_addr mask; struct in_addr via; int metric; int tag; } ; static int nrt; static RT *rts; static RT rt; static int given; #define GAVE_MASK 0x00000001 #define GAVE_VIA 0x00000002 #define GAVE_METRIC 0x00000004 #define GAVE_TAG 0x00000008 static struct sockaddr_in src_sin; static struct sockaddr_in dst_sin; static unsigned char *pkt; static int pktlen; static int sock; static int version = 0; static int aflag; static int pflag; static int bflag; static void usage(void) { fprintf(stderr,"Usage: %s [-1] [-2] [-0] [-a] [-p] [-b]\n",__progname); fprintf(stderr," src-addr[/src-port] dst-addr[/dst-port]\n"); fprintf(stderr," route-spec [route-spec ...]\n"); fprintf(stderr,"A route-spec is: dest [keyword value [keyword value ...]]\n"); fprintf(stderr,"keywords: netmask (aka mask), via, metric, tag\n"); fprintf(stderr,"netmask can also be specified with /mask on the dest argument\n"); } #ifdef NO_INET_ATON static int inet_aton(const char *s, struct in_addr *a) { unsigned long int li; li = inet_addr(s); if (li == (unsigned long int)-1) return(0); a->s_addr = li; } #endif /* can't use inet_aton here because it doesn't do the ep thing. growl. */ static int parse_d_q(const char *s, char **ep, struct in_addr *ia) { unsigned char o[4]; long int v; int n; char *e; for (n=0;n<4;n++) { if (n) { if (*s != '.') return(0); s ++; } v = strtol(s,&e,0); if ((s == e) || (v < 0) || (v > 255)) return(0); o[n] = v; s = e; } *ep = e; ia->s_addr = htonl( (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3] ); return(1); } static void parse_sin(const char *s, struct sockaddr_in *sin, const char *tag) { long int v; char *ep; sin->sin_family = AF_INET; #ifndef NO_SIN_LEN sin->sin_len = sizeof(*sin); #endif if (! parse_d_q(s,&ep,&sin->sin_addr)) { fprintf(stderr,"%s: %s address must be a dotted quad\n",__progname,tag); exit(1); } if (! *ep) return; if (*ep != '/') { fprintf(stderr,"%s: junk after %s address: %s\n",__progname,tag,ep); exit(1); } s = ep + 1; v = strtol(s,&ep,0); if (*ep || (s == ep) || (v < 0) || (v > 65535)) { fprintf(stderr,"%s: missing/invalid %s port number: %s\n",__progname,tag,s); exit(1); } sin->sin_port = htons(v); } static void key_netmask(const char *s) { char *ep; struct in_addr ia; long int v; if (given & GAVE_MASK) { fprintf(stderr,"%s: netmask specified more than once\n",__progname); exit(1); } if (parse_d_q(s,&ep,&ia)) { if (*ep) { fprintf(stderr,"%s: junk after netmask: %s\n",__progname,ep); exit(1); } rt.mask = ia; given |= GAVE_MASK; return; } if (*s == '/') { s ++; v = strtol(s,&ep,0); if (!*ep && (ep != s) && (v >= 1) && (v <= 32)) { rt.mask.s_addr = htonl((~0UL)<<(32-v)); given |= GAVE_MASK; return; } } fprintf(stderr,"%s: missing/invalid netmask: %s\n",__progname,s); exit(1); } static void key_via(const char *s) { char *ep; struct in_addr ia; if (given & GAVE_VIA) { fprintf(stderr,"%s: router specified more than once\n",__progname); exit(1); } if (parse_d_q(s,&ep,&ia)) { if (*ep) { fprintf(stderr,"%s: junk after router address: %s\n",__progname,ep); exit(1); } rt.via = ia; given |= GAVE_VIA; return; } fprintf(stderr,"%s: missing/invalid router address: %s\n",__progname,s); exit(1); } static void key_metric(const char *s) { char *ep; long int v; if (given & GAVE_METRIC) { fprintf(stderr,"%s: metric specified more than once\n",__progname); exit(1); } v = strtol(s,&ep,0); if (*ep || (ep == s) || (v < 0) || (v > 16)) { fprintf(stderr,"%s: missing/invalid metric: %s\n",__progname,s); exit(1); } rt.metric = v; given |= GAVE_METRIC; } static void key_tag(const char *s) { char *ep; long int v; if (given & GAVE_TAG) { fprintf(stderr,"%s: route tag specified more than once\n",__progname); exit(1); } v = strtol(s,&ep,0); if (*ep || (ep == s) || (v < 0) || (v > 65535)) { fprintf(stderr,"%s: missing/invalid route tag: %s\n",__progname,s); exit(1); } rt.tag = v; given |= GAVE_TAG; } static void parse_args(int ac, char **av) { char *ep; const char *s; long int v; while (1) { ac --; av ++; if (ac < 1) { usage(); exit(1); } if (!strcmp(av[0],"-1")) { version = 1; continue; } if (!strcmp(av[0],"-2")) { version = 2; continue; } if (!strcmp(av[0],"-0")) { version = 0; continue; } if (!strcmp(av[0],"-a")) { aflag = 1; continue; } if (!strcmp(av[0],"-p")) { pflag = 1; continue; } if (!strcmp(av[0],"-b")) { bflag = 1; continue; } break; } if (ac < 2) { usage(); exit(1); } parse_sin(av[0],&src_sin,"src"); parse_sin(av[1],&dst_sin,"dst"); ac -= 2; av += 2; nrt = 0; given = 0; while (1) { static struct { const char *key; void (*parsearg)(const char *); } keys[] = { { "mask", key_netmask }, { "netmask", key_netmask }, { "via", key_via }, { "metric", key_metric }, { "tag", key_tag }, { "to", 0 }, { "default", 0 }, { 0 } }; int i; if (ac < 1) break; if (!strcmp(av[0],"to")) { ac --; av ++; if (ac < 1) { fprintf(stderr,"%s: missing destination address\n",__progname); exit(1); } } if (!strcmp(av[0],"default")) { rt.to.s_addr = 0; } else if (! parse_d_q(av[0],&ep,&rt.to)) { fprintf(stderr,"%s: destination address must be a dotted quad: %s\n",__progname,av[0]); exit(1); } if (*ep) { if (*ep != '/') { fprintf(stderr,"%s: junk after destination address: %s\n",__progname,ep); exit(1); } s = ep + 1; if (! parse_d_q(s,&ep,&rt.mask)) { v = strtol(s,&ep,0); if (*ep || (s == ep) || (v < 1) || (v > 32)) { fprintf(stderr,"%s: missing/invalid destination mask: %s\n",__progname,s); exit(1); } rt.mask.s_addr = htonl((~0UL)<<(32-v)); } given |= GAVE_MASK; } ac --; av ++; while (1) { if (ac < 2) break; for (i=0;keys[i].key;i++) if (!strcmp(keys[i].key,av[0])) break; if (keys[i].key) { if (! keys[i].parsearg) break; (*keys[i].parsearg)(av[1]); ac -= 2; av += 2; continue; } if (isdigit(av[0][0])) break; fprintf(stderr,"%s: invalid keyword: %s\n",__progname,av[0]); exit(1); } rts = realloc(rts,(nrt+1)*sizeof(RT)); if (! (given & GAVE_MASK)) rt.mask.s_addr = 0; if (! (given & GAVE_VIA)) rt.via.s_addr = 0; if (! (given & GAVE_METRIC)) rt.metric = 1; if (! (given & GAVE_TAG)) rt.tag = 0; rts[nrt] = rt; nrt ++; } } static int need_v2(void) { int i; RT *r; for (i=0;imask.s_addr || r->via.s_addr || r->tag) return(1); } return(0); } static void check_version(void) { if (need_v2()) { if (version == 1) { fprintf(stderr,"%s: need RIPv2 for this set of routes\n",__progname); exit(1); } version = 2; } else { if (version == 0) version = 1; } } static void set16(void *vp, unsigned short int v) { ((unsigned char *)vp)[0] = (v >> 8) & 0xff; ((unsigned char *)vp)[1] = v & 0xff; } static void set32(void *vp, unsigned long int v) { ((unsigned char *)vp)[0] = (v >> 24) & 0xff; ((unsigned char *)vp)[1] = (v >> 16) & 0xff; ((unsigned char *)vp)[2] = (v >> 8) & 0xff; ((unsigned char *)vp)[3] = v & 0xff; } static void build_packet(void) { int px; RT *r; int i; if (nrt > 25) fprintf(stderr,"%s: warning: too many routes for a RIP packet (max 25)\n",__progname); pktlen = 4 + (20 * nrt); pkt = malloc(pktlen); pkt[0] = 2; /* command, 2=response */ pkt[1] = version; /* version */ pkt[2] = 0; /* mbz */ pkt[3] = 0; /* mbz */ px = 4; for (i=0;itag); /* route tag */ px += 2; set32(pkt+px,ntohl(r->to.s_addr)); /* route destination */ px += 4; set32(pkt+px,ntohl(r->mask.s_addr)); /* netmask */ px += 4; set32(pkt+px,ntohl(r->via.s_addr)); /* next-hop gateway */ px += 4; set32(pkt+px,r->metric); /* metric (duh!) */ px += 4; } if (px != pktlen) abort(); } static void setup_socket(void) { int on; sock = socket(AF_INET,SOCK_DGRAM,0); if (sock < 0) { fprintf(stderr,"%s: socket: %s\n",__progname,strerror(errno)); exit(1); } on = 1; if (aflag && (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0)) { fprintf(stderr,"%s: warning: SO_REUSEADDR: %s\n",__progname,strerror(errno)); } if (pflag) { #ifdef SO_REUSEPORT if (setsockopt(sock,SOL_SOCKET,SO_REUSEPORT,&on,sizeof(on)) < 0) { fprintf(stderr,"%s: warning: SO_REUSEPORT: %s\n",__progname,strerror(errno)); } #else fprintf(stderr,"%s: warning: SO_REUSEPORT not supported in this build\n",__progname); #endif } if (bflag && (setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)) < 0)) { fprintf(stderr,"%s: warning: SO_BROADCAST: %s\n",__progname,strerror(errno)); } if (bind(sock,(struct sockaddr *)&src_sin,sizeof(src_sin)) < 0) { fprintf(stderr,"%s: bind: %s\n",__progname,strerror(errno)); exit(1); } } static void sendpkt(void) { if (sendto(sock,pkt,pktlen,0,(struct sockaddr *)&dst_sin,sizeof(dst_sin)) < 0) { fprintf(stderr,"%s: warning: sendto: %s\n",__progname,strerror(errno)); } } int main(int, char **); int main(int ac, char **av) { parse_args(ac,av); check_version(); build_packet(); setup_socket(); while (1) { sendpkt(); sleep(30); } }