2 * ASCEND: @(#)filters.c 1.3 (95/07/25 00:55:30)
4 * Copyright (c) 1994 Ascend Communications, Inc.
7 * Permission to copy all or part of this material for any purpose is
8 * granted provided that the above copyright notice and this paragraph
9 * are duplicated in all copies. THIS SOFTWARE IS PROVIDED ``AS IS''
10 * AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
11 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12 * FOR A PARTICULAR PURPOSE.
18 * Alan DeKok's comments: This code SUCKS. Having a static string
19 * instead of passing function parameters is a STUPID thing to do.
21 * This code should be re-written to get rid of Ascend's copyright,
22 * and to fix all of the horrible crap of the current implementation.
25 #include <sys/types.h>
30 #include <netinet/in.h>
32 #include <sys/time.h> /* gettimeofday() */
34 #include "libradius.h"
39 * Two types of filters are supported, GENERIC and IP. The identifiers
43 #define RAD_FILTER_GENERIC 0
44 #define RAD_FILTER_IP 1
45 #define RAD_FILTER_IPX 2
48 * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
49 * starting at some offset. The length is:
51 #define RAD_MAX_FILTER_LEN 6
54 * ASCEND extensions for ABINARY filters
57 #define IPX_NODE_ADDR_LEN 6
59 typedef uint32_t IpxNet;
60 typedef unsigned char IpxNode[ IPX_NODE_ADDR_LEN ];
61 typedef unsigned short IpxSocket;
63 #if ! defined( FALSE )
65 # define TRUE (! FALSE)
69 * RadFilterComparison:
71 * An enumerated values for the IP filter port comparisons.
79 } RadFilterComparison;
84 * The binary format of an IP filter. ALL fields are stored in
87 * srcip: The source IP address.
89 * dstip: The destination IP address.
91 * srcmask: The number of leading one bits in the source address
92 * mask. Specifies the bits of interest.
94 * dstmask: The number of leading one bits in the destination
95 * address mask. Specifies the bits of interest.
97 * proto: The IP protocol number
99 * establised: A boolean value. TRUE when we care about the
100 * established state of a TCP connection. FALSE when
103 * srcport: TCP or UDP source port number.
105 * dstport: TCP or UDP destination port number.
107 * srcPortCmp: One of the values of the RadFilterComparison enumeration
108 * specifying how to compare the srcport value.
110 * dstPortCmp: One of the values of the RadFilterComparison enumeration
111 * specifying how to compare the dstport value.
113 * fill: Round things out to a dword boundary.
115 typedef struct radip {
118 unsigned char srcmask;
119 unsigned char dstmask;
121 unsigned char established;
122 unsigned short srcport;
123 unsigned short dstport;
124 unsigned char srcPortComp;
125 unsigned char dstPortComp;
126 unsigned char fill[4]; /* used to be fill[2] */
131 * The binary format of a GENERIC filter. ALL fields are stored in
132 * network byte order.
134 * srcIpxNet: Source IPX Net address
136 * srcIpxNode: Source IPX Node address
138 * srcIpxSoc: Source IPX socket address
140 * dstIpxNet: Destination IPX Net address
142 * dstIpxNode: Destination IPX Node address
144 * dstIpxSoc: Destination IPX socket address
146 * srcSocComp: Source socket compare value
148 * dstSocComp: Destination socket compare value
151 typedef struct radipx {
152 IpxNet srcIpxNet; /* LongWord */
153 IpxNode srcIpxNode; /* Byte[6] */
154 IpxSocket srcIpxSoc; /* Word */
155 IpxNet dstIpxNet; /* LongWord */
156 IpxNode dstIpxNode; /* Byte[6] */
157 IpxSocket dstIpxSoc; /* Word */
158 unsigned char srcSocComp;
159 unsigned char dstSocComp;
165 * The binary format of a GENERIC filter. ALL fields are stored in
166 * network byte order.
168 * offset: Number of bytes into packet to start comparison.
170 * len: Number of bytes to mask and compare. May not
171 * exceed RAD_MAX_FILTER_LEN.
173 * more: Boolean. If non-zero the next filter entry is
174 * also to be applied to a packet.
176 * mask: A bit mask specifying the bits to compare.
178 * value: A value to compare against the masked bits at
179 * offset in a users packet.
181 * compNeq: Defines type of comarison (Equal or Notequal)
184 * fill: Round things out to a dword boundary
186 typedef struct radgeneric {
187 unsigned short offset;
190 unsigned char mask[ RAD_MAX_FILTER_LEN ];
191 unsigned char value[ RAD_MAX_FILTER_LEN ];
192 unsigned char compNeq;
193 unsigned char fill[3]; /* used to be fill */
199 * A binary filter element. Contains either a RadIpFilter or a
200 * RadGenericFilter. All fields are stored in network byte order.
202 * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
204 * forward: TRUE if we should forward packets that match this
205 * filter, FALSE if we should drop packets that match
208 * indirection: TRUE if this is an input filter, FALSE if this is
211 * fill: Round things out to a dword boundary.
214 * ip: An ip filter entry
215 * generic: A generic filter entry
217 typedef struct filter {
219 unsigned char forward;
220 unsigned char indirection;
225 RadGenericFilter generic;
228 #define SIZEOF_RADFILTER 32
238 * Ascii names of some well known tcp/udp services.
239 * Used for filtering on a port type.
242 static KeywordStruct filterPortType[] = {
247 { "nameserver", 42 },
264 static KeywordStruct filterType[] = {
265 { "generic",RAD_FILTER_GENERIC},
266 { "ip", RAD_FILTER_IP},
267 { "ipx", RAD_FILTER_IPX},
278 FILTER_GENERIC_OFFSET,
280 FILTER_GENERIC_VALUE,
281 FILTER_GENERIC_COMPNEQ,
282 FILTER_GENERIC_COMPEQ,
291 FILTER_IPX_DST_IPXNET,
292 FILTER_IPX_DST_IPXNODE,
293 FILTER_IPX_DST_IPXSOCK,
294 FILTER_IPX_SRC_IPXNET,
295 FILTER_IPX_SRC_IPXNODE,
296 FILTER_IPX_SRC_IPXSOCK
300 static KeywordStruct filterKeywords[] = {
301 { "ip", FILTER_IP_TYPE },
302 { "generic",FILTER_GENERIC_TYPE },
304 { "out", FILTER_OUT },
305 { "forward",FILTER_FORWARD },
306 { "drop", FILTER_DROP },
307 { "dstip", FILTER_IP_DST },
308 { "srcip", FILTER_IP_SRC },
309 { "dstport",FILTER_IP_DST_PORT },
310 { "srcport",FILTER_IP_SRC_PORT },
311 { "est", FILTER_EST },
312 { "more", FILTER_MORE },
313 { "!=", FILTER_GENERIC_COMPNEQ },
314 { "==", FILTER_GENERIC_COMPEQ },
315 { "ipx", FILTER_IPX_TYPE },
316 { "dstipxnet", FILTER_IPX_DST_IPXNET },
317 { "dstipxnode", FILTER_IPX_DST_IPXNODE },
318 { "dstipxsock", FILTER_IPX_DST_IPXSOCK },
319 { "srcipxnet", FILTER_IPX_SRC_IPXNET },
320 { "srcipxnode", FILTER_IPX_SRC_IPXNODE },
321 { "srcipxsock", FILTER_IPX_SRC_IPXSOCK },
325 #define FILTER_DIRECTION 0
326 #define FILTER_DISPOSITION 1
327 #define IP_FILTER_COMPLETE 0x3 /* bits shifted by FILTER_DIRECTION */
328 /* FILTER_DISPOSITION */
330 #define IPX_FILTER_COMPLETE 0x3 /* bits shifted by FILTER_DIRECTION */
331 /* FILTER_DISPOSITION */
333 #define GENERIC_FILTER_COMPLETE 0x1c3 /* bits shifted for FILTER_DIRECTION */
334 /* FILTER_DISPOSITION, FILTER_GENERIC_OFFSET*/
335 /* FILTER_GENERIC_MASK, FILTER_GENERIC_VALUE*/
340 * Ascii name of protocols used for filtering.
343 static KeywordStruct filterProtoName[] = {
351 static KeywordStruct filterCompare[] = {
352 { ">", RAD_COMPARE_GREATER },
353 { "=", RAD_COMPARE_EQUAL },
354 { "<", RAD_COMPARE_LESS },
355 { "!=", RAD_COMPARE_NOT_EQUAL },
359 static char curString[512];
361 static int findKey ( const char *string, KeywordStruct *list );
362 static int isAllDigit ( const char *token );
363 static short a2octet ( const char *tok, char *retBuf );
364 static char defaultNetmask ( uint32_t address );
365 static int ipAddressStringToValue ( char *string, uint32_t *ipAddress,
367 static int parseIpFilter ( RadFilter *curEntry );
368 static int parseGenericFilter ( RadFilter *curEntry );
369 static int parseIpxFilter ( RadFilter *curEntry );
370 static int stringToNode ( unsigned char* dest, unsigned char* src );
375 * Given a table of keywords, it will try and match string to an
376 * entry. If it does it returns that keyword value. if no NO_TOKEN is
377 * returned. A sanity check is made for upper case characters.
379 * string: Pointer to the token to match.
381 * list: Point to the list of keywords.
383 * returns: Keyword value on a match or NO_TOKEN.
385 int findKey(const char *string, KeywordStruct *list)
388 KeywordStruct* entry;
391 len = strlen( string );
392 for( ptr = buf ; len; len--, string++ ) {
393 if( isupper( *string ) ) {
394 *ptr++ = tolower( *string );
401 while( entry->name ) {
402 if( strcmp( entry->name, buf ) == 0 ) {
407 return( entry->value );
413 * Routine checks a string to make sure all values are digits.
415 * token: Pointer to sting to check.
417 * returns: TRUE if all digits, or FALSE.
422 isAllDigit(const char *token)
428 if( isdigit( *token ) ) {
444 * Converts the ascii mask and value for generic filters into octets.
445 * It also does a sanity check to see if the string is greater than
446 * MAX_FILTER_LEN. It assumes the sting is hex with NO leading "0x"
448 * tok: Pointer to the string.
450 * retBuf: Pointer to place the octets.
452 * returns: Number of octects or -1 for error.
456 a2octet(const char *tok, char *retBuf)
458 short rc, len, val, retLen, i;
459 char buf[ RAD_MAX_FILTER_LEN *2 ];
465 if( ( len = strlen( tok ) ) <= ( RAD_MAX_FILTER_LEN*2 ) ) {
470 memset( buf, '\0', RAD_MAX_FILTER_LEN * 2 );
471 for( ; len; len-- ) {
472 if( *tok <= '9' && *tok >= '0' ) {
474 *octet++ = *tok++ - val;
475 } else if( isxdigit( *tok ) ) {
481 *octet++ = ( *tok++ - val ) + 10;
487 /* merge the values */
488 for( i = 0; i < RAD_MAX_FILTER_LEN*2; i+=2 ) {
489 *retBuf++ = (buf[i] << 4) | buf[i+1];
507 * Given an ip address this routine calculate a default netmask.
509 * address: Ip address.
511 * returns: Number of bits for the netmask
515 defaultNetmask(address)
522 } else if (( address & htonl( 0x80000000 ) ) == 0 ) {
524 } else if (( address & htonl( 0xc0000000 ) ) == htonl( 0x80000000 ) ) {
526 } else if (( address & htonl( 0xe0000000 ) ) == htonl( 0xc0000000 ) ) {
535 static char ipAddressDigits[] = "1234567890./";
537 * This functions attempts to convert an IP address in ASCII dot
538 * with an optional netmask part to a pair of IpAddress. Note:
539 * An IpAddress is always stored in network byte order.
543 * string: Pointer to a NULL terminated IP address in dot
544 * notation followed by an optional /nn to indicate
545 * the number leading of bits in the netmask.
547 * ipAddress: Pointer to an IpAddress where the converted
548 * address will be stored.
550 * netmask: Pointer to an IpAddress where the netmask
551 * will be stored. If no netmask is passed as
552 * as part of the address the default netmask will
556 * <> TRUE if valid conversion, FALSE otherwise.
558 * *ipAddress: If function returns TRUE, the IP address in NBO.
559 * *netmask: If function returns TRUE, the netmask in NBO.
563 ipAddressStringToValue(char *string, uint32_t *ipAddress,
576 /* Allow an IP address to be blanked instead of forcing entry of
577 0.0.0.0 -- the user will like it. */
579 if ( *string == 0 ) {
585 /* First just count the number of dots in the address. If there
586 are more or less than three the address is invalid. */
591 if( !strchr( ipAddressDigits, *cp) ) {
599 if ( numDots != 3 ) {
603 dst = (u_char *) ipAddress;
606 for ( i = 0; i < sizeof( *ipAddress ); i++ ) {
607 value = strtol( cp, &cp, 10 );
608 if (( value < 0 ) || ( value > 255 )) {
611 *dst++ = (u_char) value;
617 /* If there is a netmask part, parse it, otherwise figure out the
618 default netmask for this class of address. */
621 value = strtol( cp + 1, &cp, 10 );
622 if (( *cp != 0 ) || ( value < 0 ) || ( value > 32 )) {
625 *netmask = (char) value;
627 *netmask = defaultNetmask( *ipAddress );
633 * Convert a 12 digit string representation of a hex data field to a
637 stringToNode(dest, src )
648 src1 = (unsigned char *) strchr(src, 'x');
651 src1 = (unsigned char *) strchr(src,'X');
658 /* skip any leading 0x or 0X 's */
659 temp = strlen( (char*) src1 );
660 if( strlen( (unsigned char*) src1 ) != ( IPX_NODE_ADDR_LEN * 2 ) ) {
664 for ( ix = 0; ix < IPX_NODE_ADDR_LEN; ++ix ) {
665 if ( src1[ srcIx ] <= '9' ) {
666 nibble1 = src1[ srcIx ] & 0x0f;
668 nibble1 = (src1[ srcIx ] & 0x0f) + 9;
671 if ( src1[ srcIx ] <= '9' ) {
672 nibble2 = src1[ srcIx ] & 0x0f;
674 nibble2 = (src1[ srcIx ] & 0x0f) + 9;
677 ((unsigned char *) dest)[ ix ] = (unsigned char) (nibble1 << 4) + nibble2;
687 * This routine parses an IPX filter string from a RADIUS
688 * reply. The format of the string is:
690 * ipx dir action [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
691 * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
693 * Fields in [...] are optional.
696 * ipx: Keyword to designate an IPX filter. Actually this
697 * has been determined by parseFilter.
699 * dir: Filter direction. "IN" or "OUT"
701 * action: Filter action. "FORWARD" or "DROP"
703 * srcipxnet: Keyword for source IPX address.
704 * nnnn = IPX Node address.
706 * srcipxnode: Keyword for source IPX Node address.
707 * mmmmm = IPX Node Address, could be FFFFFF.
708 * A vlid ipx node number should accompany ipx net number.
710 * srcipxsoc: Keyword for source IPX socket address.
712 * cmd: One of ">" or "<" or "=" or "!=".
714 * value: Socket value to be compared against, in hex.
716 * dstipxnet: Keyword for destination IPX address.
717 * nnnn = IPX Node address.
719 * dstipxnode: Keyword for destination IPX Node address.
720 * mmmmm = IPX Node Address, could be FFFFFF.
721 * A vlid ipx node number should accompany ipx net number.
723 * dstipxsoc: Keyword for destination IPX socket address.
725 * cmd: One of ">" or "<" or "=" or "!=".
727 * value: Socket value to be compared against, in hex.
732 * curEntry: Pointer to place the filter structure
734 * returns: -1 for error or 0 for OK
739 parseIpxFilter(curEntry)
742 unsigned long elements = 0l;
747 token = strtok( NULL, " " );
749 memset( curEntry, '\0', sizeof( RadFilter ) );
750 curEntry->type = RAD_FILTER_IPX;
751 ipx = &curEntry->u.ipx;
754 tok = findKey( token, filterKeywords );
758 curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
759 elements |= (1 << FILTER_DIRECTION );
764 elements |= (1 << FILTER_DISPOSITION );
765 if( tok == FILTER_FORWARD ) {
766 curEntry->forward = TRUE;
768 curEntry->forward = FALSE;
772 case FILTER_IPX_DST_IPXNET:
773 case FILTER_IPX_SRC_IPXNET:
774 token = strtok( NULL, " " );
777 if( tok == FILTER_IPX_DST_IPXNET ) {
778 ipx->dstIpxNet = ntohl( strtol( token, 0, 16 ));
780 ipx->srcIpxNet = ntohl( strtol( token, 0, 16 ));
786 case FILTER_IPX_DST_IPXNODE:
787 case FILTER_IPX_SRC_IPXNODE:
788 token = strtok( NULL, " " );
791 if ( tok == FILTER_IPX_DST_IPXNODE) {
792 stringToNode( (unsigned char *)ipx->dstIpxNode, (unsigned char*)token );
794 stringToNode( (unsigned char *)ipx->srcIpxNode, (unsigned char*)token );
800 case FILTER_IPX_DST_IPXSOCK:
801 case FILTER_IPX_SRC_IPXSOCK:
803 RadFilterComparison cmp;
805 token = strtok( NULL, " " );
808 cmp = findKey( token, filterCompare );
809 if( cmp != NO_TOKEN ) {
810 token = strtok( NULL, " " );
812 if ( tok == FILTER_IPX_DST_IPXSOCK ) {
813 ipx->dstSocComp = cmp;
815 ntohs( (IpxSocket) strtol( token, NULL, 16 ));
817 ipx->srcSocComp = cmp;
819 = ntohs( (IpxSocket) strtol( token, NULL, 16 ));
829 /* no keyword match */
832 token = strtok( NULL, " " );
835 if( elements == IPX_FILTER_COMPLETE ) {
840 librad_log("ipx filter error: do not recognize %s in %s \n",
848 * This routine parses an IP filter string from a RADIUS
849 * reply. The format of the string is:
851 * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
852 * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ]
854 * Fields in [...] are optional.
857 * ip: Keyword to designate an IP filter. Actually this
858 * has been determined by parseFilter.
860 * dir: Filter direction. "IN" or "OUT"
862 * action: Filter action. "FORWARD" or "DROP"
864 * dstip: Keyword for destination IP address.
865 * n.n.n.n = IP address. /nn - netmask.
867 * srcip: Keyword for source IP address.
868 * n.n.n.n = IP address. /nn - netmask.
870 * proto: Optional protocol field. Either a name or
871 * number. Known names are in FilterProtoName[].
873 * dstpost: Keyword for destination port. Only valid with tcp
874 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
877 * srcpost: Keyword for source port. Only valid with tcp
878 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
881 * est: Keyword for TCP established. Valid only for tcp.
885 * curEntry: Pointer to place the filter structure
887 * returns: -1 for error or 0 for OK
892 parseIpFilter(curEntry)
896 unsigned long elements = 0l;
901 token = strtok( NULL, " " );
903 memset( curEntry, '\0', sizeof( RadFilter ) );
904 curEntry->type = RAD_FILTER_IP;
905 ip = &curEntry->u.ip;
906 ip->established = FALSE;
909 tok = findKey( token, filterKeywords );
913 curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
914 elements |= (1 << FILTER_DIRECTION );
918 elements |= (1 << FILTER_DISPOSITION );
919 if( tok == FILTER_FORWARD ) {
920 curEntry->forward = TRUE;
922 curEntry->forward = FALSE;
927 token = strtok( NULL, " " );
929 if( tok == FILTER_IP_DST ) {
931 if( ipAddressStringToValue( token,
932 &ip->dstip, (char *)&ip->dstmask ) ) {
936 if( ipAddressStringToValue( token,
937 &ip->srcip, (char *)&ip->srcmask ) ) {
943 librad_log("ip filter error: do not recognize %s in %s \n",
947 case FILTER_IP_DST_PORT:
948 case FILTER_IP_SRC_PORT:
950 RadFilterComparison cmp;
953 token = strtok( NULL, " " );
955 cmp = findKey( token, filterCompare );
956 if( cmp != NO_TOKEN ) {
957 token = strtok( NULL, " " );
959 if( isAllDigit( token ) ) {
960 port = atoi( (char *) token );
962 port = findKey( token, filterPortType );
964 if( port != (short) NO_TOKEN ) {
965 if( tok == FILTER_IP_DST_PORT ) {
966 ip->dstPortComp = cmp;
967 ip->dstport = htons( port );
969 ip->srcPortComp = cmp;
970 ip->srcport = htons( port );
977 librad_log( "ip filter error: do not recognize %s in %s \n",
983 ip->established = TRUE;
986 /* no keyword match but may match a protocol list */
987 if( isAllDigit( token ) ) {
988 tok = atoi( (char *) token );
990 tok = findKey( token, filterProtoName );
992 if( tok == NO_TOKEN ) {
993 librad_log("ip filter error: do not recognize %s in %s \n",
1000 token = strtok( NULL, " " );
1003 if( elements == IP_FILTER_COMPLETE ) {
1012 * parseGenericFilter:
1014 * This routine parses a Generic filter string from a RADIUS
1015 * reply. The format of the string is:
1017 * GENERIC dir action offset mask value [== or != ] [more]
1019 * Fields in [...] are optional.
1022 * generic: Keyword to indicate a generic filter. This
1023 * has been determined by parseFilter.
1025 * dir: Filter direction. "IN" or "OUT"
1027 * action: Filter action. "FORWARD" or "DROP"
1029 * offset: A Number. Specifies an offset into a frame
1030 * to start comparing.
1032 * mask: A hexadecimal mask of bits to compare.
1034 * value: A value to compare with the masked data.
1036 * compNeq: Defines type of comparison. ( "==" or "!=")
1039 * more: Optional keyword MORE, to represent the attachment
1040 * to the next entry.
1044 * curEntry: Pointer to place the filter structure
1046 * returns: -1 for error or 0 for OK
1051 parseGenericFilter(curEntry)
1052 RadFilter *curEntry;
1054 unsigned long elements = 0l;
1056 int gstate = FILTER_GENERIC_OFFSET;
1058 short valLen, maskLen;
1059 RadGenericFilter* gen;
1061 token = strtok( NULL, " " );
1064 memset( (char *)curEntry, '\0', sizeof( RadFilter ) );
1065 curEntry->type = RAD_FILTER_GENERIC;
1066 gen = &curEntry->u.generic;
1068 gen->compNeq = FALSE;
1071 tok = findKey( token, filterKeywords );
1075 curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
1076 elements |= (1 << FILTER_DIRECTION );
1078 case FILTER_FORWARD:
1080 elements |= (1 << FILTER_DISPOSITION );
1081 if( tok == FILTER_FORWARD ) {
1082 curEntry->forward = TRUE;
1084 curEntry->forward = FALSE;
1087 case FILTER_GENERIC_COMPNEQ:
1088 gen->compNeq = TRUE;
1090 case FILTER_GENERIC_COMPEQ:
1091 gen->compNeq = FALSE;
1094 gen->more = htons( TRUE );
1097 elements |= ( 1 << gstate );
1099 case FILTER_GENERIC_OFFSET:
1100 gstate = FILTER_GENERIC_MASK;
1101 gen->offset = htons( atoi( (char *) token ) );
1103 case FILTER_GENERIC_MASK:
1104 gstate = FILTER_GENERIC_VALUE;
1105 maskLen = a2octet( token, (char *)gen->mask );
1106 if( maskLen == (short) -1 ) {
1107 librad_log("filter mask error: %s \n", curString );
1111 case FILTER_GENERIC_VALUE:
1113 valLen = a2octet( token, (char *)gen->value );
1114 if( valLen != maskLen ) {
1115 librad_log("filter value size is not the same size as the filter mask: %s \n",
1119 gen->len = htons( valLen );
1122 librad_log("filter: do not know %s in %s \n",
1127 token = strtok( NULL, " " );
1130 if( elements == GENERIC_FILTER_COMPLETE ) {
1141 * This routine will call routines to parse entries from an ASCII format
1142 * to a binary format recognized by the Ascend boxes.
1144 * pair: Pointer to value_pair to place return.
1146 * valstr: The string to parse
1148 * return: -1 for error or 0.
1151 filterBinary(VALUE_PAIR *pair, const char *valstr)
1157 RadFilter radFil, *filt;
1158 RadGenericFilter* gen;
1159 static VALUE_PAIR *prevRadPair = NULL;
1160 char *copied_valstr;
1163 strcpy( curString, valstr );
1166 * Copy the valstr, so we don't smash it in place via strtok!
1168 copied_valstr = strdup(valstr);
1169 if (!copied_valstr) return -1;
1171 token = strtok(copied_valstr, " " );
1172 tok = findKey( token, filterType );
1173 pair->length = SIZEOF_RADFILTER;
1175 case RAD_FILTER_GENERIC:
1176 rc = parseGenericFilter( &radFil );
1179 rc = parseIpFilter( &radFil );
1181 case RAD_FILTER_IPX:
1182 rc = parseIpxFilter( &radFil );
1185 librad_log("filterBinary: unknown filter type \"%s\"", token);
1186 free(copied_valstr);
1190 free(copied_valstr);
1191 copied_valstr = NULL;
1194 * if 'more' is set then this new entry must exist, be a
1195 * FILTER_GENERIC_TYPE, direction and disposition must match for
1196 * the previous 'more' to be valid. If any should fail then TURN OFF
1200 filt = ( RadFilter * )prevRadPair->strvalue;
1201 if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
1202 ( prevRadPair->attribute != pair->attribute ) ||
1203 ( filt->indirection != radFil.indirection ) ||
1204 ( filt->forward != radFil.forward ) ) {
1205 gen = &filt->u.generic;
1207 librad_log("filterBinary: 'more' for previous entry doesn't match: %s.\n",
1212 if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
1213 if( radFil.u.generic.more ) {
1219 memcpy( pair->strvalue, (char *) &radFil, pair->length );
1225 /********************************************************************/
1228 * The following code was written specifically for the FreeRADIUS
1229 * server by Alan DeKok <aland@ox.org>, and as such, falls under
1230 * the GPL, and not under the previous Ascend license.
1233 static const char *FindValue(int value, KeywordStruct *list)
1235 KeywordStruct *entry;
1238 while (entry->name) {
1239 if (entry->value == value) {
1249 * Print an Ascend binary filter attribute to a string,
1250 * Grrr... Ascend makes the server do this work, instead
1251 * of doing it on the NAS.
1253 * Note we don't bother checking 'len' after the snprintf's.
1254 * This function should ONLY be called with a large (~1k) buffer.
1256 void print_abinary(VALUE_PAIR *vp, u_char *buffer, int len)
1262 static const char *action[] = {"drop", "forward"};
1263 static const char *direction[] = {"output", "input"};
1268 * Just for paranoia: wrong size filters get printed as octets
1270 if (vp->length != SIZEOF_RADFILTER) {
1273 for (i = 0; i < vp->length; i++) {
1274 sprintf(p, " %02x", vp->strvalue[i]);
1280 memcpy(&filter, vp->strvalue, SIZEOF_RADFILTER); /* alignment issues */
1282 len -= 3; /* account for leading & trailing quotes */
1284 i = snprintf(p, len, "%s %s %s",
1285 FindValue(filter.type, filterType),
1286 action[filter.forward & 0x01],
1287 direction[filter.indirection & 0x01]);
1294 if (filter.type == RAD_FILTER_IP) {
1295 if (filter.u.ip.dstip) {
1296 i = snprintf(p, len, " dstip %d.%d.%d.%d/%d",
1297 ((u_char *) &filter.u.ip.dstip)[0],
1298 ((u_char *) &filter.u.ip.dstip)[1],
1299 ((u_char *) &filter.u.ip.dstip)[2],
1300 ((u_char *) &filter.u.ip.dstip)[3],
1301 filter.u.ip.dstmask);
1306 if (filter.u.ip.srcip) {
1307 i = snprintf(p, len, " srcip %d.%d.%d.%d/%d",
1308 ((u_char *) &filter.u.ip.srcip)[0],
1309 ((u_char *) &filter.u.ip.srcip)[1],
1310 ((u_char *) &filter.u.ip.srcip)[2],
1311 ((u_char *) &filter.u.ip.srcip)[3],
1312 filter.u.ip.srcmask);
1317 i = snprintf(p, len, " %d", filter.u.ip.proto);
1321 if (filter.u.ip.dstPortComp) {
1322 i = snprintf(p, len, " dstport %s %d",
1323 FindValue(filter.u.ip.dstPortComp, filterCompare),
1324 ntohs(filter.u.ip.dstport));
1329 if (filter.u.ip.srcPortComp) {
1330 i = snprintf(p, len, " srcport %s %d",
1331 FindValue(filter.u.ip.srcPortComp, filterCompare),
1332 ntohs(filter.u.ip.srcport));
1338 * Handle IPX filters
1340 } else if (filter.type == RAD_FILTER_IPX) {
1341 /* print for source */
1342 if (filter.u.ipx.srcIpxNet) {
1343 i = snprintf(p, len, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
1344 ntohl(filter.u.ipx.srcIpxNet),
1345 filter.u.ipx.srcIpxNode[0], filter.u.ipx.srcIpxNode[1],
1346 filter.u.ipx.srcIpxNode[2], filter.u.ipx.srcIpxNode[3],
1347 filter.u.ipx.srcIpxNode[4], filter.u.ipx.srcIpxNode[5]);
1351 if (filter.u.ipx.srcSocComp) {
1352 i = snprintf(p, len, " srcipxsock %s 0x%04x",
1353 FindValue(filter.u.ipx.srcSocComp, filterCompare),
1354 ntohs(filter.u.ipx.srcIpxSoc));
1360 /* same for destination */
1361 if (filter.u.ipx.dstIpxNet) {
1362 i = snprintf(p, len, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
1363 ntohl(filter.u.ipx.dstIpxNet),
1364 filter.u.ipx.dstIpxNode[0], filter.u.ipx.dstIpxNode[1],
1365 filter.u.ipx.dstIpxNode[2], filter.u.ipx.dstIpxNode[3],
1366 filter.u.ipx.dstIpxNode[4], filter.u.ipx.dstIpxNode[5]);
1370 if (filter.u.ipx.dstSocComp) {
1371 i = snprintf(p, len, " dstipxsock %s 0x%04x",
1372 FindValue(filter.u.ipx.dstSocComp, filterCompare),
1373 ntohs(filter.u.ipx.dstIpxSoc));
1380 } else if (filter.type == RAD_FILTER_GENERIC) {
1383 i = snprintf(p, len, " %d ", filter.u.generic.offset);
1388 for (count = 0; count < ntohs(filter.u.generic.len); count++) {
1389 i = snprintf(p, len, "%02x", filter.u.generic.mask[count]);
1398 /* show the value */
1399 for (count = 0; count < ntohs(filter.u.generic.len); count++) {
1400 i = snprintf(p, len, "%02x", filter.u.generic.value[count]);
1405 i = snprintf(p, len, " %s", (filter.u.generic.compNeq) ? "!=" : "==");