/******************************************/ /* Functions that send and receive the IP */ /* Options Header. Types supported: */ /* - Loose Source Routing. */ /* - Strict Source Routing. */ /* - Record Routing. */ /******************************************/ #ifndef lint static const char rcsid[] = "$Id: ip_options.c,v 1.4 2000/10/04 17:40:54 slay Exp $"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifdef HAVE_NETINET_IN_SYSTM_H #include #else #ifdef HAVE_NETINET_IN_SYSTEM_H #include #endif #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_BSTRING_H #include #endif #ifdef STDC_HEADERS #include #endif #include #if defined(FREEBSD) || defined(OPENBSD) || defined(NETBSD) #include #endif #ifdef LINUX #include #ifndef KERNEL_VERSION #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #endif #else # define LINUX_VERSION_CODE 0 # define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #endif #include "ip_options.h" void print_ip_opt(void) { if ( !packet.len_ipopt ) { write_log(1,"IPOPT rx!!"); return; } if ( packet.rr ) print_rr(); else if ( verbose ) print_lssrr(); } /*******************************************/ /* Print a received Record Route IP Option */ /*******************************************/ void print_rr( void ) { u_char *cursor = ip_opt_rcv, *opt_len = NULL; static char rroute[IP_OPT_DFL]; static int rroute_len; u_int loop, len; struct in_addr gway; if ( *cursor != RR_OPT ) { write_log(1,"Sent RR -> received %d (len %d)", *cursor, *(++cursor)); return; } ++cursor; opt_len = cursor; if ( (*opt_len > IP_OPT_DFL) || (*opt_len < 8)) { write_log(1,"Over/Undersized IP Options length!!"); return; } if (*opt_len==rroute_len && !memcmp(ip_opt_rcv, rroute, *opt_len) ) { write_log(1," (same song)"); return; } rroute_len=*opt_len; copymem(ip_opt_rcv, rroute, *opt_len); cursor+=2; len = 3; loop = 1; while ( len <= opt_len_rcv ) { if ( *cursor == END_OPT ) return; copymem( cursor, (u_char *)&gway, 4); write_log(1,"\n RR%d = %s", loop++, inet_ntoa(gway)); cursor+=4; len+=4; } } /*******************************************/ /* Print a received Loose or Strict Source */ /* Route Option. */ /*******************************************/ void print_lssrr( void ) { u_char *cursor = ip_opt_rcv, symbol; static char sr[IP_OPT_DFL]; static int sr_len; u_int len=0, flag=0; struct in_addr gway; if ( (opt_len_rcv > IP_OPT_DFL) || (opt_len_rcv < 3)) { write_log(1,"Over/Undersized IP Options length!!"); return; } if (opt_len_rcv==sr_len && !memcmp(ip_opt_rcv, sr, opt_len_rcv) ) { write_log(1," (same song)"); return; } sr_len=opt_len_rcv; copymem(ip_opt_rcv, sr, opt_len_rcv); while( (*cursor == NOOP_OPT) && (len <= opt_len_rcv) ) { cursor++; len++; } if ( (*cursor != LSRR_OPT) && (*cursor != SSRR_OPT) ) { write_log(1,"IPOPT received %d (len %d)!!", *cursor, *(++cursor)); return; } symbol = (*cursor == LSRR_OPT)?LOOSE_SYM:STRICT_SYM; cursor+=3; len+=3; write_log(1,"\n SR= "); while ( len < opt_len_rcv ) { if ( *cursor == END_OPT ) return; copymem( cursor, (u_char *)&gway, 4); if ( flag ) write_log(1,"%c", symbol ); write_log(1,"%s", inet_ntoa(gway) ); flag = 1; cursor+=4; len+=4; } } /************************************/ /* Does the destination host have a */ /* '!' or a '@'? */ /* If yes then make a LSRR or SSRR */ /* else make a RR option. */ /* **********************************/ void ip_opt_control( char *host ) { u_char *punt, *ip_opt; if ( ( punt = strpbrk(host, SR_SYMS) ) ) { packet.ipopt = (char *)malloc(IP_OPT_DFL); if (!packet.ipopt) go_out_error(3,"Out of memory on ip_opt_control"); initmem(packet.ipopt, IP_OPT_DFL); packet.rr = 0; if ( *punt == LOOSE_SYM ) /* LSRR */ { make_ipopt( host, LSRR_OPT ); } if ( *punt == STRICT_SYM ) /* SSRR */ { make_ipopt( host, SSRR_OPT ); } } else { if ( packet.rr ) /* If RR activated... */ { packet.len_ipopt = IP_OPT_DFL; ip_opt = packet.ipopt = (char *)malloc(IP_OPT_DFL); initmem(packet.ipopt, IP_OPT_DFL); *ip_opt++ = RR_OPT; /* RR IP Option Code */ *ip_opt++ = IP_OPT_DFL - 1; /* Length */ *ip_opt = 4; /* IP Option Offset */ } } } /*******************************/ /* Parse the gateways for a */ /* LSRR or SSRR IP option and */ /* build the IP Option header. */ /*******************************/ void make_ipopt( char *host, int code ) { u_char *opt_cursor, *opt_len, *host_cursor, *cursor, symbol; u_long *gway_cursor; #ifdef SOLARIS u_short aux=0; #endif int hay_host = 0, i; symbol = ( code == LSRR_OPT)?LOOSE_SYM:STRICT_SYM; opt_cursor = packet.ipopt = (char *)malloc(IP_OPT_DFL); initmem(packet.ipopt, IP_OPT_DFL); *opt_cursor++ = NOOP_OPT; *opt_cursor++ = code; /* IP Option Code */ opt_len = opt_cursor++; /* Length. Filled in later */ *opt_cursor++ = 4; /* IP Option Pointer */ cursor = host_cursor = host; while ( *cursor && (cont_gways < 10) ) { if ( *cursor == symbol ) { if ( hay_host ) { if ( cont_gways == 9 ) go_out(1, "Can't handle more than 10 gateways"); *cursor=0; hay_host = 0; if ( exist_host( host_cursor, &gway_ip[cont_gways]) ) go_out(1, "Wrong gateway address/name on IP %s option -> %s", (code==LSRR_OPT)?"LSRR":"SSRR", host_cursor); cont_gways++; host_cursor=cursor+1; } else host_cursor++; } else hay_host = 1; cursor++; } if ( hay_host ) { if ( exist_host( host_cursor, &gway_ip[cont_gways]) ) go_out(1, "Wrong gateway address/name on IP %s option -> %s", (code==LSRR_OPT)?"LSRR":"SSRR", host_cursor); cont_gways++; } if ( cont_gways < 2 ) /* If only 1 host discard IP Options header */ { free(packet.ipopt); packet.ipopt = NULL; return; } gway_cursor = (u_long *)opt_cursor; #ifdef SOLARIS if (!packet.mac_src) aux=1; *opt_len = ( (cont_gways - aux) << 2 ) + 3 ; for (i=aux; i <= (cont_gways-1); i++) #else *opt_len = ( (cont_gways - 1) << 2 ) + 3 ; for (i=1; i <= (cont_gways-1); i++) #endif { copymem((char *)&gway_ip[i], (char *)gway_cursor, 4); gway_cursor++; } packet.len_ipopt = *opt_len + 1; } /***************************************/ /* Verify if Source Routing is enabled */ /* on BSD systems. */ /* Return -1 on error. */ /* Return 1 if SRouting enabled. */ /* Return 0 if SRouting disabled. */ /***************************************/ #if defined(FREEBSD) || defined(NETBSD) #define SR "net.inet.ip.accept_sourceroute" u_char vrfy_sr(void) { u_int sroute; size_t len; len = sizeof(sroute); if ( sysctlbyname( SR, &sroute, &len, NULL, 0) == -1 ) return -1; return((sroute)?1:0); } #endif /* Verify Source Routing on BSD systems */ /***************************************/ /* Verify if Source Routing is enabled */ /* on Linux >= 2.2.x systems. */ /* Return -1 on error. */ /* Return 1 if SRouting is enabled. */ /* Return 0 if SRouting is disabled. */ /***************************************/ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) u_char vrfy_sr(void) { FILE *fp; u_int sroute; char *path1="/proc/sys/net/ipv4/conf/"; char *path2="/accept_source_route"; char *path3="/proc/sys/net/ipv4/conf/all/accept_source_route"; char *iface=packet.listen2dev?packet.listen2dev:packet.iface2route.name; char *path2proc=(char *)calloc(64,1); if (!path2proc) go_out_error(3, "Out of memory on path2proc"); if ( (strlen(path1)+strlen(iface)+strlen(path2)) > 64 ) { free(path2proc); return -1; } strncpy(path2proc,path1,strlen(path1)); strncat(path2proc,iface,strlen(iface)); strncat(path2proc,path2,strlen(path2)); #ifdef DEBUG printf("PATH2PROC = %s\n",path2proc); #endif if ((fp=fopen( path2proc, "r")) == NULL) { printf("error fopen\n"); return -1; } if ( (sroute=fgetc(fp)) == EOF ) { printf("error fgetc\n"); fclose(fp); free(path2proc); return -1; } fclose(fp); free(path2proc); if (sroute==48) return 0; if ((fp=fopen( path3, "r")) == NULL) return -1; if ( (sroute=fgetc(fp)) == EOF ) { fclose(fp); return -1; } fclose(fp); return((sroute==48)?0:1); } #endif /* Verify Source Routing on Linux >= 2.2.x systems */