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.
29 #include "libradius.h"
32 #include <netinet/in.h>
38 * Two types of filters are supported, GENERIC and IP. The identifiers
42 #define RAD_FILTER_GENERIC 0
43 #define RAD_FILTER_IP 1
44 #define RAD_FILTER_IPX 2
47 * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
48 * starting at some offset. The length is:
50 #define RAD_MAX_FILTER_LEN 6
53 * ASCEND extensions for ABINARY filters
56 #define IPX_NODE_ADDR_LEN 6
58 typedef uint32_t IpxNet;
59 typedef unsigned char IpxNode[ IPX_NODE_ADDR_LEN ];
60 typedef unsigned short IpxSocket;
62 #if ! defined( FALSE )
64 # define TRUE (! FALSE)
68 * RadFilterComparison:
70 * An enumerated values for the IP filter port comparisons.
78 } RadFilterComparison;
83 * The binary format of an IP filter. ALL fields are stored in
86 * srcip: The source IP address.
88 * dstip: The destination IP address.
90 * srcmask: The number of leading one bits in the source address
91 * mask. Specifies the bits of interest.
93 * dstmask: The number of leading one bits in the destination
94 * address mask. Specifies the bits of interest.
96 * proto: The IP protocol number
98 * establised: A boolean value. TRUE when we care about the
99 * established state of a TCP connection. FALSE when
102 * srcport: TCP or UDP source port number.
104 * dstport: TCP or UDP destination port number.
106 * srcPortCmp: One of the values of the RadFilterComparison enumeration
107 * specifying how to compare the srcport value.
109 * dstPortCmp: One of the values of the RadFilterComparison enumeration
110 * specifying how to compare the dstport value.
112 * fill: Round things out to a dword boundary.
114 typedef struct radip {
117 unsigned char srcmask;
118 unsigned char dstmask;
120 unsigned char established;
121 unsigned short srcport;
122 unsigned short dstport;
123 unsigned char srcPortComp;
124 unsigned char dstPortComp;
125 unsigned char fill[4]; /* used to be fill[2] */
130 * The binary format of a GENERIC filter. ALL fields are stored in
131 * network byte order.
133 * srcIpxNet: Source IPX Net address
135 * srcIpxNode: Source IPX Node address
137 * srcIpxSoc: Source IPX socket address
139 * dstIpxNet: Destination IPX Net address
141 * dstIpxNode: Destination IPX Node address
143 * dstIpxSoc: Destination IPX socket address
145 * srcSocComp: Source socket compare value
147 * dstSocComp: Destination socket compare value
150 typedef struct radipx {
151 IpxNet srcIpxNet; /* LongWord */
152 IpxNode srcIpxNode; /* Byte[6] */
153 IpxSocket srcIpxSoc; /* Word */
154 IpxNet dstIpxNet; /* LongWord */
155 IpxNode dstIpxNode; /* Byte[6] */
156 IpxSocket dstIpxSoc; /* Word */
157 unsigned char srcSocComp;
158 unsigned char dstSocComp;
164 * The binary format of a GENERIC filter. ALL fields are stored in
165 * network byte order.
167 * offset: Number of bytes into packet to start comparison.
169 * len: Number of bytes to mask and compare. May not
170 * exceed RAD_MAX_FILTER_LEN.
172 * more: Boolean. If non-zero the next filter entry is
173 * also to be applied to a packet.
175 * mask: A bit mask specifying the bits to compare.
177 * value: A value to compare against the masked bits at
178 * offset in a users packet.
180 * compNeq: Defines type of comarison (Equal or Notequal)
183 * fill: Round things out to a dword boundary
185 typedef struct radgeneric {
186 unsigned short offset;
189 unsigned char mask[ RAD_MAX_FILTER_LEN ];
190 unsigned char value[ RAD_MAX_FILTER_LEN ];
191 unsigned char compNeq;
192 unsigned char fill[3]; /* used to be fill */
198 * A binary filter element. Contains either a RadIpFilter or a
199 * RadGenericFilter. All fields are stored in network byte order.
201 * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
203 * forward: TRUE if we should forward packets that match this
204 * filter, FALSE if we should drop packets that match
207 * indirection: TRUE if this is an input filter, FALSE if this is
210 * fill: Round things out to a dword boundary.
213 * ip: An ip filter entry
214 * generic: A generic filter entry
216 typedef struct filter {
218 unsigned char forward;
219 unsigned char indirection;
224 RadGenericFilter generic;
227 #define SIZEOF_RADFILTER 32
237 * Ascii names of some well known tcp/udp services.
238 * Used for filtering on a port type.
240 * ??? What the heck is wrong with getservbyname?
242 static const KeywordStruct filterPortType[] = {
247 { "nameserver", 42 },
264 static const 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 const 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.
342 * ??? What the heck is wrong with getprotobyname?
344 static const KeywordStruct filterProtoName[] = {
353 static const KeywordStruct filterCompare[] = {
354 { ">", RAD_COMPARE_GREATER },
355 { "=", RAD_COMPARE_EQUAL },
356 { "<", RAD_COMPARE_LESS },
357 { "!=", RAD_COMPARE_NOT_EQUAL },
361 static int findKey ( const char *string, const 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 ( const char *curString, RadFilter *curEntry );
368 static int parseGenericFilter ( const char *curString, RadFilter *curEntry );
369 static int parseIpxFilter ( const char *curString, 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, const KeywordStruct *list)
388 const KeywordStruct* entry;
391 len = strlen( string );
392 for( ptr = buf ; len; len--, string++ ) {
393 if( isupper( (int) *string ) ) {
394 *ptr++ = tolower( (int) *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( (int) *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( (int) *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 const 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 < (int)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((char *)src, 'x');
651 src1 = (unsigned char *) strchr((char *)src,'X');
658 /* skip any leading 0x or 0X 's */
659 temp = strlen( (char*) src1 );
660 if( strlen( (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(curString, curEntry)
740 const char *curString;
743 unsigned long elements = 0l;
748 token = strtok( NULL, " " );
750 memset( curEntry, '\0', sizeof( RadFilter ) );
751 curEntry->type = RAD_FILTER_IPX;
752 ipx = &curEntry->u.ipx;
755 tok = findKey( token, filterKeywords );
759 curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
760 elements |= (1 << FILTER_DIRECTION );
765 elements |= (1 << FILTER_DISPOSITION );
766 if( tok == FILTER_FORWARD ) {
767 curEntry->forward = TRUE;
769 curEntry->forward = FALSE;
773 case FILTER_IPX_DST_IPXNET:
774 case FILTER_IPX_SRC_IPXNET:
775 token = strtok( NULL, " " );
778 if( tok == FILTER_IPX_DST_IPXNET ) {
779 ipx->dstIpxNet = ntohl( strtol( token, 0, 16 ));
781 ipx->srcIpxNet = ntohl( strtol( token, 0, 16 ));
787 case FILTER_IPX_DST_IPXNODE:
788 case FILTER_IPX_SRC_IPXNODE:
789 token = strtok( NULL, " " );
792 if ( tok == FILTER_IPX_DST_IPXNODE) {
793 stringToNode( (unsigned char *)ipx->dstIpxNode, (unsigned char*)token );
795 stringToNode( (unsigned char *)ipx->srcIpxNode, (unsigned char*)token );
801 case FILTER_IPX_DST_IPXSOCK:
802 case FILTER_IPX_SRC_IPXSOCK:
804 RadFilterComparison cmp;
806 token = strtok( NULL, " " );
809 cmp = findKey( token, filterCompare );
810 if( cmp != (RadFilterComparison)NO_TOKEN ) {
811 token = strtok( NULL, " " );
813 if ( tok == FILTER_IPX_DST_IPXSOCK ) {
814 ipx->dstSocComp = cmp;
816 ntohs( (IpxSocket) strtol( token, NULL, 16 ));
818 ipx->srcSocComp = cmp;
820 = ntohs( (IpxSocket) strtol( token, NULL, 16 ));
830 /* no keyword match */
833 token = strtok( NULL, " " );
836 if( elements == IPX_FILTER_COMPLETE ) {
841 librad_log("ipx filter error: do not recognize %s in %s \n",
849 * This routine parses an IP filter string from a RADIUS
850 * reply. The format of the string is:
852 * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
853 * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ]
855 * Fields in [...] are optional.
858 * ip: Keyword to designate an IP filter. Actually this
859 * has been determined by parseFilter.
861 * dir: Filter direction. "IN" or "OUT"
863 * action: Filter action. "FORWARD" or "DROP"
865 * dstip: Keyword for destination IP address.
866 * n.n.n.n = IP address. /nn - netmask.
868 * srcip: Keyword for source IP address.
869 * n.n.n.n = IP address. /nn - netmask.
871 * proto: Optional protocol field. Either a name or
872 * number. Known names are in FilterProtoName[].
874 * dstpost: Keyword for destination port. Only valid with tcp
875 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
878 * srcpost: Keyword for source port. Only valid with tcp
879 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
882 * est: Keyword for TCP established. Valid only for tcp.
886 * curEntry: Pointer to place the filter structure
888 * returns: -1 for error or 0 for OK
893 parseIpFilter(curString, curEntry)
894 const char *curString;
898 unsigned long elements = 0l;
903 token = strtok( NULL, " " );
905 memset( curEntry, '\0', sizeof( RadFilter ) );
906 curEntry->type = RAD_FILTER_IP;
907 ip = &curEntry->u.ip;
908 ip->established = FALSE;
911 tok = findKey( token, filterKeywords );
915 curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
916 elements |= (1 << FILTER_DIRECTION );
920 elements |= (1 << FILTER_DISPOSITION );
921 if( tok == FILTER_FORWARD ) {
922 curEntry->forward = TRUE;
924 curEntry->forward = FALSE;
929 token = strtok( NULL, " " );
931 if( tok == FILTER_IP_DST ) {
933 if( ipAddressStringToValue( token,
934 &ip->dstip, (char *)&ip->dstmask ) ) {
938 if( ipAddressStringToValue( token,
939 &ip->srcip, (char *)&ip->srcmask ) ) {
945 librad_log("ip filter error: do not recognize %s in %s \n",
949 case FILTER_IP_DST_PORT:
950 case FILTER_IP_SRC_PORT:
952 RadFilterComparison cmp;
955 token = strtok( NULL, " " );
957 cmp = findKey( token, filterCompare );
958 if( cmp != (RadFilterComparison)NO_TOKEN ) {
959 token = strtok( NULL, " " );
961 if( isAllDigit( token ) ) {
962 port = atoi( (char *) token );
964 port = findKey( token, filterPortType );
966 if( port != (short) NO_TOKEN ) {
967 if( tok == FILTER_IP_DST_PORT ) {
968 ip->dstPortComp = cmp;
969 ip->dstport = htons( port );
971 ip->srcPortComp = cmp;
972 ip->srcport = htons( port );
979 librad_log( "ip filter error: do not recognize %s in %s \n",
985 ip->established = TRUE;
988 /* no keyword match but may match a protocol list */
989 if( isAllDigit( token ) ) {
990 tok = atoi( (char *) token );
992 tok = findKey( token, filterProtoName );
994 if( tok == NO_TOKEN ) {
995 librad_log("ip filter error: do not recognize %s in %s \n",
1002 token = strtok( NULL, " " );
1005 if( elements == IP_FILTER_COMPLETE ) {
1014 * parseGenericFilter:
1016 * This routine parses a Generic filter string from a RADIUS
1017 * reply. The format of the string is:
1019 * GENERIC dir action offset mask value [== or != ] [more]
1021 * Fields in [...] are optional.
1024 * generic: Keyword to indicate a generic filter. This
1025 * has been determined by parseFilter.
1027 * dir: Filter direction. "IN" or "OUT"
1029 * action: Filter action. "FORWARD" or "DROP"
1031 * offset: A Number. Specifies an offset into a frame
1032 * to start comparing.
1034 * mask: A hexadecimal mask of bits to compare.
1036 * value: A value to compare with the masked data.
1038 * compNeq: Defines type of comparison. ( "==" or "!=")
1041 * more: Optional keyword MORE, to represent the attachment
1042 * to the next entry.
1046 * curEntry: Pointer to place the filter structure
1048 * returns: -1 for error or 0 for OK
1053 parseGenericFilter(curString, curEntry)
1054 const char *curString;
1055 RadFilter *curEntry;
1057 unsigned long elements = 0l;
1059 int gstate = FILTER_GENERIC_OFFSET;
1061 short valLen, maskLen;
1062 RadGenericFilter* gen;
1064 token = strtok( NULL, " " );
1067 memset( (char *)curEntry, '\0', sizeof( RadFilter ) );
1068 curEntry->type = RAD_FILTER_GENERIC;
1069 gen = &curEntry->u.generic;
1071 gen->compNeq = FALSE;
1074 tok = findKey( token, filterKeywords );
1078 curEntry->indirection = tok == FILTER_IN ? TRUE: FALSE;
1079 elements |= (1 << FILTER_DIRECTION );
1081 case FILTER_FORWARD:
1083 elements |= (1 << FILTER_DISPOSITION );
1084 if( tok == FILTER_FORWARD ) {
1085 curEntry->forward = TRUE;
1087 curEntry->forward = FALSE;
1090 case FILTER_GENERIC_COMPNEQ:
1091 gen->compNeq = TRUE;
1093 case FILTER_GENERIC_COMPEQ:
1094 gen->compNeq = FALSE;
1097 gen->more = htons( TRUE );
1100 elements |= ( 1 << gstate );
1102 case FILTER_GENERIC_OFFSET:
1103 gstate = FILTER_GENERIC_MASK;
1104 gen->offset = htons( atoi( (char *) token ) );
1106 case FILTER_GENERIC_MASK:
1107 gstate = FILTER_GENERIC_VALUE;
1108 maskLen = a2octet( token, (char *)gen->mask );
1109 if( maskLen == (short) -1 ) {
1110 librad_log("filter mask error: %s \n", curString );
1114 case FILTER_GENERIC_VALUE:
1116 valLen = a2octet( token, (char *)gen->value );
1117 if( valLen != maskLen ) {
1118 librad_log("filter value size is not the same size as the filter mask: %s \n",
1122 gen->len = htons( valLen );
1125 librad_log("filter: do not know %s in %s \n",
1130 token = strtok( NULL, " " );
1133 if( elements == GENERIC_FILTER_COMPLETE ) {
1144 * This routine will call routines to parse entries from an ASCII format
1145 * to a binary format recognized by the Ascend boxes.
1147 * pair: Pointer to value_pair to place return.
1149 * valstr: The string to parse
1151 * return: -1 for error or 0.
1154 filterBinary(VALUE_PAIR *pair, const char *valstr)
1160 RadFilter radFil, *filt;
1161 RadGenericFilter* gen;
1162 static VALUE_PAIR *prevRadPair = NULL;
1163 char *copied_valstr;
1168 * Copy the valstr, so we don't smash it in place via strtok!
1170 copied_valstr = strdup(valstr);
1171 if (!copied_valstr) return -1;
1173 token = strtok(copied_valstr, " " );
1174 tok = findKey( token, filterType );
1175 pair->length = SIZEOF_RADFILTER;
1177 case RAD_FILTER_GENERIC:
1178 rc = parseGenericFilter( valstr, &radFil );
1181 rc = parseIpFilter( valstr, &radFil );
1183 case RAD_FILTER_IPX:
1184 rc = parseIpxFilter( valstr, &radFil );
1187 librad_log("filterBinary: unknown filter type \"%s\"", token);
1188 free(copied_valstr);
1192 free(copied_valstr);
1193 copied_valstr = NULL;
1196 * if 'more' is set then this new entry must exist, be a
1197 * FILTER_GENERIC_TYPE, direction and disposition must match for
1198 * the previous 'more' to be valid. If any should fail then TURN OFF
1202 filt = ( RadFilter * )prevRadPair->strvalue;
1203 if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
1204 ( prevRadPair->attribute != pair->attribute ) ||
1205 ( filt->indirection != radFil.indirection ) ||
1206 ( filt->forward != radFil.forward ) ) {
1207 gen = &filt->u.generic;
1209 librad_log("filterBinary: 'more' for previous entry doesn't match: %s.\n",
1214 if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
1215 if( radFil.u.generic.more ) {
1221 memcpy( pair->strvalue, (char *) &radFil, pair->length );
1227 /********************************************************************/
1230 * The following code was written specifically for the FreeRADIUS
1231 * server by Alan DeKok <aland@ox.org>, and as such, falls under
1232 * the GPL, and not under the previous Ascend license.
1235 static const char *FindValue(unsigned int value, const KeywordStruct *list)
1237 const KeywordStruct *entry;
1240 while (entry->name) {
1241 if (entry->value == value) {
1251 * Print an Ascend binary filter attribute to a string,
1252 * Grrr... Ascend makes the server do this work, instead
1253 * of doing it on the NAS.
1255 * Note we don't bother checking 'len' after the snprintf's.
1256 * This function should ONLY be called with a large (~1k) buffer.
1258 void print_abinary(VALUE_PAIR *vp, u_char *buffer, int len)
1264 static const char *action[] = {"drop", "forward"};
1265 static const char *direction[] = {"output", "input"};
1270 * Just for paranoia: wrong size filters get printed as octets
1272 if (vp->length > SIZEOF_RADFILTER) {
1275 for (i = 0; i < vp->length; i++) {
1276 sprintf(p, " %02x", vp->strvalue[i]);
1282 memcpy(&filter, vp->strvalue, SIZEOF_RADFILTER); /* alignment issues */
1284 len -= 3; /* account for leading & trailing quotes */
1286 i = snprintf(p, len, "%s %s %s",
1287 FindValue(filter.type, filterType),
1288 direction[filter.indirection & 0x01],
1289 action[filter.forward & 0x01]);
1297 if (filter.type == RAD_FILTER_IP) {
1299 i = snprintf(p, len, " %s",
1300 FindValue(filter.u.ip.proto, filterProtoName));
1304 if (filter.u.ip.dstip) {
1305 i = snprintf(p, len, " dstip %d.%d.%d.%d/%d",
1306 ((u_char *) &filter.u.ip.dstip)[0],
1307 ((u_char *) &filter.u.ip.dstip)[1],
1308 ((u_char *) &filter.u.ip.dstip)[2],
1309 ((u_char *) &filter.u.ip.dstip)[3],
1310 filter.u.ip.dstmask);
1315 if (filter.u.ip.srcip) {
1316 i = snprintf(p, len, " srcip %d.%d.%d.%d/%d",
1317 ((u_char *) &filter.u.ip.srcip)[0],
1318 ((u_char *) &filter.u.ip.srcip)[1],
1319 ((u_char *) &filter.u.ip.srcip)[2],
1320 ((u_char *) &filter.u.ip.srcip)[3],
1321 filter.u.ip.srcmask);
1326 if (filter.u.ip.dstPortComp) {
1327 i = snprintf(p, len, " dstport %s %d",
1328 FindValue(filter.u.ip.dstPortComp, filterCompare),
1329 ntohs(filter.u.ip.dstport));
1334 if (filter.u.ip.srcPortComp) {
1335 i = snprintf(p, len, " srcport %s %d",
1336 FindValue(filter.u.ip.srcPortComp, filterCompare),
1337 ntohs(filter.u.ip.srcport));
1342 if (filter.u.ip.established) {
1343 i = snprintf(p, len, " est");
1349 * Handle IPX filters
1351 } else if (filter.type == RAD_FILTER_IPX) {
1352 /* print for source */
1353 if (filter.u.ipx.srcIpxNet) {
1354 i = snprintf(p, len, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
1355 (unsigned int)ntohl(filter.u.ipx.srcIpxNet),
1356 filter.u.ipx.srcIpxNode[0], filter.u.ipx.srcIpxNode[1],
1357 filter.u.ipx.srcIpxNode[2], filter.u.ipx.srcIpxNode[3],
1358 filter.u.ipx.srcIpxNode[4], filter.u.ipx.srcIpxNode[5]);
1362 if (filter.u.ipx.srcSocComp) {
1363 i = snprintf(p, len, " srcipxsock %s 0x%04x",
1364 FindValue(filter.u.ipx.srcSocComp, filterCompare),
1365 ntohs(filter.u.ipx.srcIpxSoc));
1371 /* same for destination */
1372 if (filter.u.ipx.dstIpxNet) {
1373 i = snprintf(p, len, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
1374 (unsigned int)ntohl(filter.u.ipx.dstIpxNet),
1375 filter.u.ipx.dstIpxNode[0], filter.u.ipx.dstIpxNode[1],
1376 filter.u.ipx.dstIpxNode[2], filter.u.ipx.dstIpxNode[3],
1377 filter.u.ipx.dstIpxNode[4], filter.u.ipx.dstIpxNode[5]);
1381 if (filter.u.ipx.dstSocComp) {
1382 i = snprintf(p, len, " dstipxsock %s 0x%04x",
1383 FindValue(filter.u.ipx.dstSocComp, filterCompare),
1384 ntohs(filter.u.ipx.dstIpxSoc));
1391 } else if (filter.type == RAD_FILTER_GENERIC) {
1394 i = snprintf(p, len, " %d ", filter.u.generic.offset);
1399 for (count = 0; count < ntohs(filter.u.generic.len); count++) {
1400 i = snprintf(p, len, "%02x", filter.u.generic.mask[count]);
1409 /* show the value */
1410 for (count = 0; count < ntohs(filter.u.generic.len); count++) {
1411 i = snprintf(p, len, "%02x", filter.u.generic.value[count]);
1416 i = snprintf(p, len, " %s", (filter.u.generic.compNeq) ? "!=" : "==");