home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / IPFILTER.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  12KB  |  632 lines

  1. /*
  2.  *   Packet filtering code for KA9Q.
  3.  *
  4.  *   Copyright 1992 David F. Mischler
  5.  *   This code may be freely distributed as long as this copyright
  6.  *   notice is preserved.
  7.  */
  8.  
  9. /****************************************************************************
  10. *    $Id: ipfilter.c 1.2 93/07/16 11:45:46 ROOT_DOS Exp $
  11. *    14 Jun 93    1.2        GT    Fix warnings.                                    *
  12. ****************************************************************************/
  13.  
  14. #include <limits.h>
  15.  
  16. #ifndef _FILTER_H
  17. #include "filter.h"
  18. #endif
  19.  
  20. #ifndef _IFACE_H
  21. #include "iface.h"
  22. #endif
  23.  
  24. #ifndef _ICMP_H
  25. #include "icmp.h"
  26. #endif
  27.  
  28. #ifndef _IP_H
  29. #include "ip.h"
  30. #endif
  31.  
  32. #ifndef _NETUSER_H
  33. #include "netuser.h"
  34. #endif
  35.  
  36. #include    "socket.h"
  37.  
  38. #define SDWIDTH 21    /* Width of a displayed source or destination */
  39.  
  40. /*
  41.  *   Information for TCP header kludges.
  42.  */
  43. #define CODEBITS_ACK    16
  44. #define CODEBITS_OFFSET 13
  45. #define CODEBITS_SYN    2
  46. #define SRC_PORT_OFFSET 0    /* TCP & UDP */
  47. #define DST_PORT_OFFSET 2    /* TCP & UDP */
  48.  
  49.  
  50. /*
  51.  *   Function to return a non-zero value if an IP packet
  52.  *   matches a filter entry.
  53.  */
  54. static
  55. int
  56. pkt_ip( struct mbuf *bp, struct ip *ip, struct filter *fp )
  57. {
  58.     /*
  59.      *   If source address doesn't match then get out.
  60.      */
  61.     if ( fp->src.addr == ( ip->source & fp->src.mask ) ) {
  62.         if ( fp->src.exclude )
  63.             return 0;
  64.     }
  65.     else {
  66.         if ( fp->src.exclude == 0 )
  67.             return 0;
  68.     }
  69.  
  70.     /*
  71.      *   If destination address doesn't match then get out.
  72.      */
  73.     if ( fp->dest.addr == ( ip->dest & fp->dest.mask ) ) {
  74.         if ( fp->dest.exclude )
  75.             return 0;
  76.     }
  77.     else {
  78.         if ( fp->dest.exclude == 0 )
  79.             return 0;
  80.     }
  81.  
  82.     return 1;
  83. }
  84.  
  85.  
  86. /*
  87.  *   Function to return a non-zero value if an ICMP packet
  88.  *   matches a filter entry.
  89.  */
  90. static
  91. int
  92. pkt_icmp( struct mbuf *bp, struct ip *ip, struct filter *fp )
  93. {
  94.     /*
  95.      *   Check protocol type.
  96.      */
  97.     if ( ip->protocol != ICMP_PTCL )
  98.         return 0;
  99.  
  100.     /*
  101.      *   Check source & destination addresses.
  102.      */
  103.     return pkt_ip( bp, ip, fp );
  104. }
  105.  
  106. /*
  107.  *   Function to return a non-zero value if an ICMP REDIRECT
  108.  *   packet matches a filter entry.
  109.  */
  110. static
  111. int
  112. pkt_icmprd( struct mbuf *bp, struct ip *ip, struct filter *fp )
  113. {
  114.     /*
  115.      *   Check protocol type and source & destination addresses.
  116.      */
  117.     if ( pkt_icmp( bp, ip, fp ) == 0 )
  118.         return 0;
  119.  
  120.     /*
  121.      *   Check ICMP message type.
  122.      */
  123.     if ( bp->data[ 0 ] == ICMP_REDIRECT )
  124.         return 1;
  125.  
  126.     return 0;
  127. }
  128.  
  129.  
  130. /*
  131.  *   Function to return a non-zero value if an ICMP packet
  132.  *   other than a REDIRECT matches a filter entry.
  133.  */
  134. static
  135. int
  136. pkt_icmpxrd( struct mbuf *bp, struct ip *ip, struct filter *fp )
  137. {
  138.     /*
  139.      *   Check protocol type and source & destination addresses.
  140.      */
  141.     if ( pkt_icmp( bp, ip, fp ) == 0 )
  142.         return 0;
  143.  
  144.     /*
  145.      *   Check ICMP message type.
  146.      */
  147.     if ( bp->data[ 0 ] != ICMP_REDIRECT )
  148.         return 1;
  149.  
  150.     return 0;
  151. }
  152.  
  153.  
  154. /*
  155.  *   Function to return a non-zero value if a TCP packet
  156.  *   matches a filter entry.
  157.  */
  158. static
  159. int
  160. pkt_tcp( struct mbuf *bp, struct ip *ip, struct filter *fp )
  161. {
  162. unsigned short    port;
  163.  
  164.     /*
  165.      *   Check protocol type.
  166.      */
  167.     if ( ip->protocol != TCP_PTCL )
  168.         return 0;
  169.  
  170.     /*
  171.      *   Check source & destination addresses.
  172.      */
  173.     if ( pkt_ip( bp, ip, fp ) == 0 )
  174.         return 0;
  175.  
  176.     /*
  177.      *   Check source port.
  178.      */
  179.     if ( fp->src.port ) {
  180.         port = get16( &bp->data[SRC_PORT_OFFSET] );
  181.         if ( fp->src.port > port || fp->src.hiport < port )
  182.             return 0;
  183.     }
  184.  
  185.     /*
  186.      *   Check destination port.
  187.      */
  188.     if ( fp->dest.port ) {
  189.         port = get16( &bp->data[DST_PORT_OFFSET] );
  190.         if ( fp->dest.port > port || fp->dest.hiport < port )
  191.             return 0;
  192.     }
  193.     return 1;
  194. }
  195.  
  196.  
  197. /*
  198.  *   Function to return a non-zero value if a TCP packet
  199.  *   with SYN set and ACK clear matches a filter entry.
  200.  */
  201. static
  202. int
  203. pkt_tcpsyn( struct mbuf *bp, struct ip *ip, struct filter *fp )
  204. {
  205. unsigned char    codebits;
  206.  
  207.     /*
  208.      *   Check for TCP protocol type and matching addresses.
  209.      */
  210.     if ( pkt_tcp( bp, ip, fp ) == 0 )
  211.         return 0;
  212.  
  213.     /*
  214.      *   Check that SYN is set and ACK is clear.
  215.      */
  216.     codebits = bp->data[ CODEBITS_OFFSET ];
  217.     if ( ( codebits & CODEBITS_SYN ) && ( codebits & CODEBITS_ACK ) == 0 )
  218.         return 1;
  219.  
  220.     return 0;
  221. }
  222.  
  223.  
  224. /*
  225.  *   Function to return a non-zero value if a TCP packet
  226.  *   with SYN clear or ACK set matches a filter entry.
  227.  */
  228. static
  229. int
  230. pkt_tcpxsyn( struct mbuf *bp, struct ip *ip, struct filter *fp )
  231. {
  232. unsigned char    codebits;
  233.  
  234.     /*
  235.      *   Check for TCP protocol type and matching addresses.
  236.      */
  237.     if ( pkt_tcp( bp, ip, fp ) == 0 )
  238.         return 0;
  239.  
  240.     /*
  241.      *   Check that SYN is clear or ACK is set.
  242.      */
  243.     codebits = bp->data[ CODEBITS_OFFSET ];
  244.     if ( ( codebits & CODEBITS_SYN ) == 0 || ( codebits & CODEBITS_ACK ) )
  245.         return 1;
  246.  
  247.     return 0;
  248. }
  249.  
  250.  
  251. /*
  252.  *   Function to return a non-zero value if a UDP packet
  253.  *   matches a filter entry.
  254.  */
  255. static
  256. int
  257. pkt_udp( struct mbuf *bp, struct ip *ip, struct filter *fp )
  258. {
  259. unsigned short    port;
  260.  
  261.     /*
  262.      *   Check protocol type.
  263.      */
  264.     if ( ip->protocol != UDP_PTCL )
  265.         return 0;
  266.  
  267.     /*
  268.      *   Check source & destination addresses.
  269.      */
  270.     if ( pkt_ip( bp, ip, fp ) == 0 )
  271.         return 0;
  272.  
  273.     /*
  274.      *   Check source port.
  275.      */
  276.     if ( fp->src.port ) {
  277.         port = get16( &bp->data[SRC_PORT_OFFSET] );
  278.         if ( fp->src.port > port || fp->src.hiport < port )
  279.             return 0;
  280.     }
  281.  
  282.     /*
  283.      *   Check destination port.
  284.      */
  285.     if ( fp->dest.port ) {
  286.         port = get16( &bp->data[DST_PORT_OFFSET] );
  287.         if ( fp->dest.port > port || fp->dest.hiport < port )
  288.             return 0;
  289.     }
  290.     return 1;
  291. }
  292.  
  293.  
  294. /*
  295.  *   Table of filter actions (indexes must match FILTER_ACTION_*).
  296.  */
  297. static char *Acts[] = {
  298.     "?", "deny", "permit"
  299. };
  300.  
  301. /*
  302.  *   Table of packet type names and matching functions.
  303.  */
  304. static struct {
  305.     char *name;
  306.     int  (*function) __ARGS((struct mbuf *bp, struct ip *ip, struct filter *fp));
  307. } Types[] = {
  308.     { "*",        pkt_ip },        /* Any IP packet    */
  309.     { "icmp",        pkt_icmp },    /* Any ICMP packet    */
  310.     { "icmprd",    pkt_icmprd },    /* ICMP redirect    */
  311.     { "icmpxrd",    pkt_icmpxrd },    /* ICMP except redirect    */
  312.     { "tcp",        pkt_tcp },    /* Any TCP packet    */
  313.     { "tcpsyn",    pkt_tcpsyn },    /* TCP SYN packet    */
  314.     { "tcpxsyn",    pkt_tcpxsyn },    /* TCP except SYN    */
  315.     { "udp",        pkt_udp },    /* Any UDP packet    */
  316.     { NULL,        NULL }
  317. };
  318.  
  319. /*
  320.  *   Function to parse a filter source or destination spec.
  321.  *   A non-zero return value indicates a syntax problem.
  322.  */
  323. static
  324. int
  325. sdparse( char *p, struct filtersd *sdp )
  326. {
  327. char    *addrp;        /* Pointer to address specification    */
  328. char    *bitp;        /* Pointer to bit count            */
  329.  
  330.     sdp->addr = 0L;
  331.     sdp->mask = ~0L;
  332.     sdp->bits = 32;
  333.     sdp->exclude = 0;
  334.     sdp->port = 0;
  335.     sdp->hiport = 0;
  336.  
  337.     /*
  338.      *   Look for '!' in address to specify address exclusion.
  339.      */
  340.     if ( *p == '!' ) {
  341.         p += 1;
  342.         sdp->exclude = 1;
  343.     }
  344.     addrp = p;
  345.  
  346.     /*
  347.      *   Look for '/' in spec to separate number of bits.
  348.      */
  349.     if ((bitp = strchr( p, '/' )) != 0) {
  350.         *bitp++ = '\0';
  351.         p = bitp;
  352.     }
  353.  
  354.     /*
  355.      *   Look for ':' in spec to separate port number.
  356.      */
  357.     if ((p = strchr( p, ':' )) != 0) {
  358.         *p++ = '\0';
  359.         sdp->hiport = sdp->port = atoi( p );
  360.  
  361.         /*
  362.          *   '+' in port spec indicates >= port.
  363.          */
  364.         if ( strchr( p, '+' ) )
  365.             sdp->hiport = USHRT_MAX;
  366.         /*
  367.          *   '-' in port spec indicates port range.
  368.          */
  369.         else if ((p = strchr( p, '-' )) != 0) {
  370.             p += 1;
  371.             sdp->hiport = atoi( p );
  372.         }
  373.         if ( sdp->port > sdp->hiport ) {
  374.             tprintf( "Bad port range\n" );
  375.             return -1;
  376.         }
  377.     }
  378.  
  379.     /*
  380.      *   Evaluate number of bits if necessary.
  381.      */
  382.     if ( bitp )
  383.         sdp->mask <<= ( 32 - (sdp->bits = atoi( bitp )) );
  384.  
  385.     /*
  386.      *   Evaluate host/net address.
  387.      */
  388.     if ( strcmp( "*", addrp ) == 0 ) {
  389.         sdp->bits = 0;
  390.         sdp->mask = 0L;
  391.     }
  392.     else {
  393.         if ( ( sdp->addr = resolve( addrp ) ) == 0 ) {
  394.             tprintf( Badhost, addrp );
  395.             return -1;
  396.         }
  397.     }
  398.  
  399.     sdp->addr &= sdp->mask;
  400.  
  401.     return 0;
  402. }
  403.  
  404. /*
  405.  *   Function to list a source or destination address.
  406.  */
  407. static
  408. void
  409. listaddr( struct filtersd *sdp )
  410. {
  411. int    i = 0;
  412.  
  413.     if ( sdp->exclude ) {
  414.         tputc( '!' );
  415.         i = 1;
  416.     }
  417.  
  418.     if ( sdp->addr == 0L && sdp->bits == 0 ) {
  419.         tputc( '*' );
  420.         i += 1;
  421.     }
  422.     else {
  423.         i += tprintf( "%s", inet_ntoa( sdp->addr ) );
  424.         if ( sdp->bits != 32 )
  425.             i += tprintf( "/%d", sdp->bits );
  426.     }
  427.  
  428.     if ( sdp->port ) {
  429.         i += tprintf( ":%u", sdp->port );
  430.  
  431.         if ( sdp->hiport == USHRT_MAX ) {
  432.             tputc( '+' );
  433.             i += 1;
  434.         }
  435.         else if ( sdp->hiport > sdp->port )
  436.             i += tprintf( "-%u", sdp->hiport );
  437.     }
  438.         
  439.     for ( ; i < SDWIDTH ; i++ )
  440.         tputc( ' ' );
  441. }
  442.  
  443. /*
  444.  *   Function to list a single filter entry.
  445.  */
  446. static
  447. void
  448. listfilter( struct filter *fp, char *iface, char *direct )
  449. {
  450. int    i;
  451.  
  452.     tprintf( "%s %-6s %-3s ", iface, Acts[fp->action], direct );
  453.     for ( i = 0 ; Types[i].name ; i++ ) {
  454.         if ( Types[i].function == fp->type ) {
  455.             tprintf( "%-7s ", Types[i].name );
  456.             break;
  457.         }
  458.     }
  459.  
  460.     listaddr( &fp->src );
  461.     tputc( ' ' );
  462.     listaddr( &fp->dest );
  463.     tprintf( " %lu\n", fp->matches );
  464. }
  465.  
  466. /*
  467.  *  Function to process the IP FILTER command.
  468.  */
  469. int
  470. doipfilter( int argc, char *argv[], void *p )
  471. {
  472. int        action;
  473. struct filter    *fp;    /* Filter entry pointer            */
  474. struct filter    **fpp;    /* Pointer to filter entry pointer    */
  475. struct iface    *ifp;    /* Interface structure pointer        */
  476. int        i;
  477. int        (*type)();
  478. struct filtersd    src,dest;
  479.  
  480.  
  481.     /*
  482.      *   Make sure interface is good.
  483.      */
  484.     if (( ifp = if_lookup( argv[1] ) ) == NULLIF ) {
  485.         tprintf( "Interface \"%s\" unknown\n", argv[1] );
  486.         return 1;
  487.     }
  488.  
  489.     /*
  490.      *   Check action.
  491.      */
  492.     if ( strcmp(argv[2],"delete") == 0 ) {
  493.         /*
  494.          *   Delete entire filter set.
  495.          */
  496.         while ( ifp->infilter ) {
  497.             fp = ifp->infilter;
  498.             ifp->infilter = fp->next;
  499.             free( (char *) fp );
  500.         }
  501.         while ( ifp->outfilter ) {
  502.             fp = ifp->outfilter;
  503.             ifp->outfilter = fp->next;
  504.             free( (char *) fp );
  505.         }
  506.         return 0;
  507.     }
  508.     else if ( strcmp(argv[2],"list") == 0 ) {
  509.         /*
  510.          *   List entire filter set.
  511.          */
  512.         fp = ifp->infilter;
  513.         while ( fp ) {
  514.             listfilter( fp, ifp->name, "in" );
  515.             fp = fp->next;
  516.         }
  517.         fp = ifp->outfilter;
  518.         while ( fp ) {
  519.             listfilter( fp, ifp->name, "out" );
  520.             fp = fp->next;
  521.         }
  522.         return 0;
  523.     }
  524.     else if ( strcmp(argv[2],"deny") == 0 ) {
  525.         action = FILTER_ACTION_DENY;
  526.     }
  527.     else if ( strcmp(argv[2],"permit") == 0 ) {
  528.         action = FILTER_ACTION_PERMIT;
  529.     }
  530.     else {
  531.         tprintf( "Unknown action \"%s\"\n", argv[2] );
  532.         return 2;
  533.     }
  534.  
  535.     /*
  536.      *   Complain if not enough arguments.
  537.      */
  538.     if ( argc < 7 ) {
  539.         tprintf("ip filter <iface> <act> <dir> <type> <src> <dest>\n");
  540.         return -1;
  541.     }
  542.  
  543.     /*
  544.      *   Check direction.
  545.      */
  546.     if ( strncmp(argv[3],"in",2) == 0 ) {
  547.         fpp = &ifp->infilter;
  548.     }
  549.     else if ( strncmp(argv[3],"out",3) == 0 ) {
  550.         fpp = &ifp->outfilter;
  551.     }
  552.     else {
  553.         tprintf( "Unknown direction \"%s\"\n", argv[3] );
  554.         return 3;
  555.     }
  556.  
  557.     /*
  558.      *   Check packet type.
  559.      */
  560.     for ( i = 0 ; Types[i].name ; i++ ) {
  561.         if ( strcmp(argv[4],Types[i].name) == 0 ) {
  562.             type = Types[i].function;
  563.             break;
  564.         }
  565.     }
  566.     if ( Types[i].name == NULL ) {
  567.         tprintf( "Unknown packet type \"%s\"\n", argv[4] );
  568.         return 4;
  569.     }
  570.  
  571.     /*
  572.      *   Parse source specification.
  573.      */
  574.     if ( sdparse( argv[5], &src ) )
  575.         return 5;
  576.  
  577.     /*
  578.      *   Parse destination specification.
  579.      */
  580.     if ( sdparse( argv[6], &dest ) )
  581.         return 6;
  582.  
  583.     /*
  584.      *   Append filter entry to list.
  585.      */
  586.     while ( *fpp )
  587.         fpp = &((*fpp)->next);
  588.  
  589.     *fpp = fp = (struct filter *) callocw( 1, sizeof( struct filter ) );
  590.     fp->action = action;
  591.     fp->type = type;
  592.     fp->src = src;
  593.     fp->dest = dest;
  594.  
  595.     return 0;
  596. }
  597.  
  598. /*
  599.  *  Function to apply a filter specification to a packet.
  600.  *  A non-zero return indicates that the packet should be dropped.
  601.  */
  602. int
  603. ip_filter(struct mbuf *bp, struct ip *ip, struct filter *fp)
  604. {
  605.     /*
  606.      *   Pass all IP fragments except the first.
  607.      */
  608.     if ( ip->offset != 0 )
  609.         return 0;
  610.  
  611.     /*
  612.      *   Walk the filter list until an entry matches the packet.
  613.      */
  614.     for ( ; fp ; fp = fp->next ) {
  615.         /*
  616.          *   If packet doesn't match try the next entry.
  617.          */
  618.         if ( (*fp->type)( bp, ip, fp ) == 0 )
  619.             continue;
  620.  
  621.         fp->matches += 1;
  622.  
  623.         /*
  624.          *   Take specified action.
  625.          */
  626.         if ( fp->action == FILTER_ACTION_PERMIT )
  627.             return 0;
  628.         return -1;
  629.     }
  630.     return 1;    /* Deny all packets not explicitly permitted    */
  631. }
  632.