2 * filters.c Routines to parse Ascend's filter attributes.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2003 The FreeRADIUS server project
23 static const char rcsid[] = "$Id$";
29 #include "libradius.h"
31 #ifdef HAVE_NETINET_IN_H
32 #include <netinet/in.h>
36 * Two types of filters are supported, GENERIC and IP. The identifiers
40 #define RAD_FILTER_GENERIC 0
41 #define RAD_FILTER_IP 1
42 #define RAD_FILTER_IPX 2
45 * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
46 * starting at some offset. The length is:
48 #define RAD_MAX_FILTER_LEN 6
51 * ASCEND extensions for ABINARY filters
54 #define IPX_NODE_ADDR_LEN 6
56 #if ! defined( FALSE )
58 # define TRUE (! FALSE)
64 * The binary format of an IP filter. ALL fields are stored in
67 * srcip: The source IP address.
69 * dstip: The destination IP address.
71 * srcmask: The number of leading one bits in the source address
72 * mask. Specifies the bits of interest.
74 * dstmask: The number of leading one bits in the destination
75 * address mask. Specifies the bits of interest.
77 * proto: The IP protocol number
79 * established: A boolean value. TRUE when we care about the
80 * established state of a TCP connection. FALSE when
83 * srcport: TCP or UDP source port number.
85 * dstport: TCP or UDP destination port number.
87 * srcPortCmp: One of the values of the RadFilterComparison
88 * enumeration, specifying how to compare the
91 * dstPortCmp: One of the values of the RadFilterComparison
92 * enumeration, specifying how to compare the
95 * fill: Round things out to a int16_t boundary.
97 typedef struct ascend_ip_filter_t {
108 unsigned char fill[4]; /* used to be fill[2] */
109 } ascend_ip_filter_t;
115 * net: IPX Net address
117 * node: IPX Node address
119 * socket: IPX socket address
121 typedef struct ascend_ipx_net_t {
123 uint8_t node[IPX_NODE_ADDR_LEN];
128 * ascend_ipx_filter_t
130 * The binary format of an IPX filter. ALL fields are stored in
131 * network byte order.
133 * src: Source net, node, and socket.
135 * dst: Destination net, node, and socket.
137 * srcSocComp: Source socket compare value
139 * dstSocComp: Destination socket compare value
141 typedef struct ascend_ipx_filter_t {
142 ascend_ipx_net_t src;
143 ascend_ipx_net_t dst;
146 } ascend_ipx_filter_t;
150 * ascend_generic_filter_t
152 * The binary format of a GENERIC filter. ALL fields are stored in
153 * network byte order.
155 * offset: Number of bytes into packet to start comparison.
157 * len: Number of bytes to mask and compare. May not
158 * exceed RAD_MAX_FILTER_LEN.
160 * more: Boolean. If non-zero the next filter entry is
161 * also to be applied to a packet.
163 * mask: A bit mask specifying the bits to compare.
165 * value: A value to compare against the masked bits at
166 * offset in a users packet.
168 * compNeq: Defines type of comarison (Equal or Notequal)
171 * fill: Round things out to a dword boundary
173 typedef struct ascend_generic_filter_t {
177 uint8_t mask[ RAD_MAX_FILTER_LEN ];
178 uint8_t value[ RAD_MAX_FILTER_LEN ];
180 uint8_t fill[3]; /* used to be fill[1] */
181 } ascend_generic_filter_t;
186 * A binary filter element. Contains one of ascend_ip_filter_t,
187 * ascend_ipx_filter_t, or ascend_generic_filter_t.
189 * All fields are stored in network byte order.
191 * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
193 * forward: TRUE if we should forward packets that match this
194 * filter, FALSE if we should drop packets that match
197 * direction: TRUE if this is an input filter, FALSE if this is
200 * fill: Round things out to a dword boundary.
203 * ip: An ip filter entry
204 * generic: A generic filter entry
206 typedef struct ascend_filter_t {
212 ascend_ip_filter_t ip;
213 ascend_ipx_filter_t ipx;
214 ascend_generic_filter_t generic;
217 #define SIZEOF_RADFILTER 32
222 * Ascii names of some well known tcp/udp services.
223 * Used for filtering on a port type.
225 * ??? What the heck is wrong with getservbyname?
227 static const LRAD_NAME_NUMBER filterPortType[] = {
232 { "nameserver", 42 },
249 static const LRAD_NAME_NUMBER filterType[] = {
250 { "generic", RAD_FILTER_GENERIC},
251 { "ip", RAD_FILTER_IP},
252 { "ipx", RAD_FILTER_IPX},
263 FILTER_GENERIC_OFFSET,
265 FILTER_GENERIC_VALUE,
266 FILTER_GENERIC_COMPNEQ,
267 FILTER_GENERIC_COMPEQ,
276 FILTER_IPX_DST_IPXNET,
277 FILTER_IPX_DST_IPXNODE,
278 FILTER_IPX_DST_IPXSOCK,
279 FILTER_IPX_SRC_IPXNET,
280 FILTER_IPX_SRC_IPXNODE,
281 FILTER_IPX_SRC_IPXSOCK
285 static const LRAD_NAME_NUMBER filterKeywords[] = {
286 { "ip", FILTER_IP_TYPE },
287 { "generic", FILTER_GENERIC_TYPE },
289 { "out", FILTER_OUT },
290 { "forward", FILTER_FORWARD },
291 { "drop", FILTER_DROP },
292 { "dstip", FILTER_IP_DST },
293 { "srcip", FILTER_IP_SRC },
294 { "dstport", FILTER_IP_DST_PORT },
295 { "srcport", FILTER_IP_SRC_PORT },
296 { "est", FILTER_EST },
297 { "more", FILTER_MORE },
298 { "!=", FILTER_GENERIC_COMPNEQ },
299 { "==", FILTER_GENERIC_COMPEQ },
300 { "ipx", FILTER_IPX_TYPE },
301 { "dstipxnet", FILTER_IPX_DST_IPXNET },
302 { "dstipxnode", FILTER_IPX_DST_IPXNODE },
303 { "dstipxsock", FILTER_IPX_DST_IPXSOCK },
304 { "srcipxnet", FILTER_IPX_SRC_IPXNET },
305 { "srcipxnode", FILTER_IPX_SRC_IPXNODE },
306 { "srcipxsock", FILTER_IPX_SRC_IPXSOCK },
313 * Ascii name of protocols used for filtering.
315 * ??? What the heck is wrong with getprotobyname?
317 static const LRAD_NAME_NUMBER filterProtoName[] = {
328 * RadFilterComparison:
330 * An enumerated values for the IP filter port comparisons.
337 RAD_COMPARE_NOT_EQUAL
338 } RadFilterComparison;
340 static const LRAD_NAME_NUMBER filterCompare[] = {
341 { "<", RAD_COMPARE_LESS },
342 { "=", RAD_COMPARE_EQUAL },
343 { ">", RAD_COMPARE_GREATER },
344 { "!=", RAD_COMPARE_NOT_EQUAL },
350 * String split routine. Splits an input string IN PLACE
351 * into pieces, based on spaces.
353 static int str2argv(char *str, char **argv, int max_argc)
358 if (argc >= max_argc) return argc;
360 while (*str == ' ') *(str++) = '\0';
362 if (!*str) return argc;
367 while (*str && (*str != ' ')) str++;
375 * hex2bin converts hexadecimal strings into binary
377 * Hmm... there are a number of such functions in the source.
378 * maybe we want to make a library function?
380 static int hex2bin(const char *str, uint8_t *bin, size_t length)
383 const char *letters = "0123456789ABCDEFabcdef";
386 * Must be byte aligned, not nibble aligned.
389 if ((len & 0x01) != 0) return -1;
392 * Input string is too long to fit. Don't even bother
395 if ((len / 2) > length) return -1;
398 * Input string contains non-hex characters, die.
400 if (strspn(str, letters) != len) return -1;
406 c1 = memchr(letters, toupper((int) *(str++)), 16);
407 c2 = memchr(letters, toupper((int) *(str++)), 16);
409 *(bin++) = ((c1-letters)<<4) + (c2-letters);
418 * ascend_parse_ipx_net
420 * srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]
422 static int ascend_parse_ipx_net(int argc, char **argv,
423 ascend_ipx_net_t *net, uint8_t *comp)
428 if (argc < 3) return -1;
431 * Parse the net, which is a hex number.
433 net->net = htonl(strtol(argv[0], NULL, 16));
438 token = lrad_str2int(filterKeywords, argv[1], -1);
440 case FILTER_IPX_SRC_IPXNODE:
441 case FILTER_IPX_DST_IPXNODE:
449 * Can have a leading "0x" or "0X"
452 if ((memcmp(p, "0X", 2) == 0) ||
453 (memcmp(p, "0x", 2) == 0)) p += 2;
456 * Node must be 6 octets long.
458 token = hex2bin(p, net->node, IPX_NODE_ADDR_LEN);
459 if (token != IPX_NODE_ADDR_LEN) return -1;
464 if (argc == 3) return 3;
467 * Can't be too little or too much.
469 if (argc != 6) return -1;
474 token = lrad_str2int(filterKeywords, argv[3], -1);
476 case FILTER_IPX_SRC_IPXSOCK:
477 case FILTER_IPX_DST_IPXSOCK:
485 * Parse the command "<", ">", "=" or "!="
487 token = lrad_str2int(filterCompare, argv[4], -1);
489 case RAD_COMPARE_LESS:
490 case RAD_COMPARE_EQUAL:
491 case RAD_COMPARE_GREATER:
492 case RAD_COMPARE_NOT_EQUAL:
503 token = strtoul(argv[5], NULL, 16);
504 if (token > 65535) return -1;
507 net->socket = htons(net->socket);
511 * Everything's OK, we parsed 6 entries.
517 * ascend_parse_ipx_filter
519 * This routine parses an IPX filter string from a string.
520 * The format of the string is:
522 * [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
523 * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
525 * Fields in [...] are optional.
528 * srcipxnet: Keyword for source IPX address.
529 * nnnn = IPX Node address.
531 * srcipxnode: Keyword for source IPX Node address.
532 * mmmmm = IPX Node Address, could be FFFFFF.
533 * A vlid ipx node number should accompany ipx net number.
535 * srcipxsoc: Keyword for source IPX socket address.
537 * cmd: One of ">" or "<" or "=" or "!=".
539 * value: Socket value to be compared against, in hex.
541 * dstipxnet: Keyword for destination IPX address.
542 * nnnn = IPX Node address.
544 * dstipxnode: Keyword for destination IPX Node address.
545 * mmmmm = IPX Node Address, could be FFFFFF.
546 * A valid ipx node number should accompany ipx net number.
548 * dstipxsoc: Keyword for destination IPX socket address.
550 * cmd: One of ">" or "<" or "=" or "!=".
552 * value: Socket value to be compared against, in hex.
554 static int ascend_parse_ipx(int argc, char **argv, ascend_ipx_filter_t *filter)
561 * We may have nothing, in which case we simply return.
563 if (argc == 0) return 0;
566 * Must have "net N node M"
568 if (argc < 4) return -1;
570 while ((argc > 0) && (flags != 0x03)) {
571 token = lrad_str2int(filterKeywords, argv[0], -1);
573 case FILTER_IPX_SRC_IPXNET:
574 if (flags & 0x01) return -1;
575 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
577 &(filter->srcSocComp));
578 if (rcode < 0) return -1;
584 case FILTER_IPX_DST_IPXNET:
585 if (flags & 0x02) return -1;
586 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
588 &(filter->dstSocComp));
589 if (rcode < 0) return -1;
596 librad_log("Unknown string \"%s\" in IPX data filter",
603 * Arguments left over: die.
605 if (argc != 0) return -1;
615 * Parse an IP address and optionally a netmask, to a uint32_t.
617 * ipaddr should already be initialized to zero.
618 * ipaddr is in network byte order.
620 * Returns -1 on error, or the number of bits in the netmask, otherwise.
622 static int ascend_parse_ipaddr(uint32_t *ipaddr, char *str)
627 uint32_t netmask = 0;
633 while (*str && (count < 4) && (netmask == 0)) {
639 case '0': case '1': case '2': case '3':
640 case '4': case '5': case '6': case '7':
643 ip[count] += (*str) - '0';
648 case '.': /* dot between IP numbers. */
650 if (ip[count] > 255) return -1;
653 * 24, 16, 8, 0, done.
655 *ipaddr |= (ip[count] << (8 * (3 - count)));
659 case '/': /* netmask */
662 if ((masklen < 0) || (masklen > 32)) return -1;
663 str += strspn(str, "0123456789");
669 librad_log("Invalid character in IP address");
672 } /* loop over one character */
673 } /* loop until the count hits 4 */
678 * Do the last one, too.
680 if (ip[count] > 255) return -1;
683 * 24, 16, 8, 0, done.
685 *ipaddr |= (ip[count] << (8 * (3 - count)));
689 * We've hit the end of the IP address, and there's something
690 * else left over: die.
695 * Set the default netmask.
700 } else if ((*ipaddr & 0x80000000) == 0) {
702 } else if ((*ipaddr & 0xc0000000) == 0x80000000) {
704 } else if ((*ipaddr & 0xe0000000) == 0xc0000000) {
711 *ipaddr = htonl(*ipaddr);
716 * ascend_parse_port: Parse a comparator and port.
718 * Returns -1 on error, or the comparator.
720 static int ascend_parse_port(uint16_t *port, char *compare, char *str)
722 int rcode, token = -1;
725 * There MUST be a comparison string.
727 rcode = lrad_str2int(filterCompare, compare, -1);
728 if (rcode < 0) return rcode;
730 if (strspn(str, "0123456789") == strlen(str)) {
733 token = lrad_str2int(filterPortType, str, -1);
736 if ((token < 0) || (token > 65535)) return -1;
739 *port = htons(*port);
748 * This routine parses an IP filter string from a RADIUS
749 * reply. The format of the string is:
751 * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
752 * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ]
754 * Fields in [...] are optional.
756 * dstip: Keyword for destination IP address.
757 * n.n.n.n = IP address. /nn - netmask.
759 * srcip: Keyword for source IP address.
760 * n.n.n.n = IP address. /nn - netmask.
762 * proto: Optional protocol field. Either a name or
763 * number. Known names are in FilterProtoName[].
765 * dstport: Keyword for destination port. Only valid with tcp
766 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
769 * srcport: Keyword for source port. Only valid with tcp
770 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
773 * est: Keyword for TCP established. Valid only for tcp.
776 static int ascend_parse_ip(int argc, char **argv, ascend_ip_filter_t *filter)
783 * We may have nothing, in which case we simply return.
785 if (argc == 0) return 0;
788 * There may, or may not, be src & dst IP's in the string.
791 while ((argc > 0) && (flags != 7)) {
792 token = lrad_str2int(filterKeywords, argv[0], -1);
795 if (flags & 0x01) return -1;
796 if (argc < 2) return -1;
798 rcode = ascend_parse_ipaddr(&filter->srcip, argv[1]);
799 if (rcode < 0) return rcode;
801 filter->srcmask = rcode;
808 if (flags & 0x02) return -1;
809 if (argc < 2) return -1;
811 rcode = ascend_parse_ipaddr(&filter->dstip, argv[1]);
812 if (rcode < 0) return rcode;
814 filter->dstmask = rcode;
821 * Should be protocol, ASCII or otherwise.
824 if (strspn(argv[0], "0123456789") == strlen(argv[0])) {
825 token = atoi(argv[0]);
827 token = lrad_str2int(filterProtoName, argv[0], -1);
829 librad_log("Unknown IP protocol \"%s\" in IP data filter",
834 filter->proto = token;
835 flags = 0x07; /* MUST have parsed everything. */
841 } /* looking for src/dst IP, and proto */
844 * Done looking for everything, return.
846 if (argc == 0) return 0;
849 * There may, or may not, be src & dst ports in the string.
852 while ((argc > 0) && (flags != 7)) {
853 token = lrad_str2int(filterKeywords, argv[0], -1);
855 case FILTER_IP_SRC_PORT:
856 if (flags & 0x01) return -1;
857 if (argc < 3) return -1;
859 rcode = ascend_parse_port(&filter->srcport,
861 if (rcode < 0) return rcode;
862 filter->srcPortComp = rcode;
869 case FILTER_IP_DST_PORT:
870 if (flags & 0x02) return -1;
871 if (argc < 3) return -1;
873 rcode = ascend_parse_port(&filter->dstport,
875 if (rcode < 0) return rcode;
876 filter->dstPortComp = rcode;
884 * Look for established connections.
887 filter->established = 1;
897 librad_log("Unknown string \"%s\" in IP data filter",
902 } /* looking for src/dst port */
905 * We should have parsed everything by now.
908 librad_log("Unknown extra string \"%s\" in IP data filter",
918 * ascend_parse_generic
920 * This routine parses a Generic filter string from a RADIUS
921 * reply. The format of the string is:
923 * generic dir action offset mask value [== or != ] [more]
925 * Fields in [...] are optional.
927 * offset: A Number. Specifies an offset into a frame
928 * to start comparing.
930 * mask: A hexadecimal mask of bits to compare.
932 * value: A value to compare with the masked data.
934 * compNeq: Defines type of comparison. ( "==" or "!=")
937 * more: Optional keyword MORE, to represent the attachment
940 static int ascend_parse_generic(int argc, char **argv,
941 ascend_generic_filter_t *filter)
948 * We may have nothing, in which case we simply return.
950 if (argc == 0) return 0;
953 * We need at least "offset mask value"
955 if (argc < 3) return -1;
958 * No more than optional comparison and "more"
960 if (argc > 5) return -1;
963 * Offset is a uint16_t number.
965 if (strspn(argv[0], "0123456789") != strlen(argv[0])) return -1;
967 rcode = atoi(argv[0]);
968 if (rcode > 65535) return -1;
970 filter->offset = rcode;
971 filter->offset = htons(filter->offset);
973 rcode = hex2bin(argv[1], filter->mask, sizeof(filter->mask));
974 if (rcode < 0) return -1;
976 token = hex2bin(argv[2], filter->value, sizeof(filter->value));
977 if (token < 0) return -1;
980 * The mask and value MUST be the same length.
982 if (rcode != token) return -1;
985 filter->len = htons(filter->len);
988 * Nothing more. Exit.
990 if (argc == 3) return 0;
997 token = lrad_str2int(filterKeywords, argv[0], -1);
999 case FILTER_GENERIC_COMPNEQ:
1000 if (flags & 0x01) return -1;
1001 filter->compNeq = TRUE;
1004 case FILTER_GENERIC_COMPEQ:
1005 if (flags & 0x01) return -1;
1006 filter->compNeq = FALSE;
1011 if (flags & 0x02) return -1;
1012 filter->more = htons( 1 );
1017 librad_log("Invalid string \"%s\" in generic data filter",
1033 * This routine will call routines to parse entries from an ASCII format
1034 * to a binary format recognized by the Ascend boxes.
1036 * pair: Pointer to value_pair to place return.
1038 * valstr: The string to parse
1040 * return: -1 for error or 0.
1043 ascend_parse_filter(VALUE_PAIR *pair)
1049 ascend_filter_t filter;
1054 * Rather than printing specific error messages, we create
1055 * a general one here, which won't be used if the function
1058 librad_log("Text is not in proper format");
1061 * Tokenize the input string in the VP.
1063 * Once the filter is *completely* parsed, then we will
1064 * over-write it with the final binary filter.
1066 argc = str2argv(pair->strvalue, argv, 32);
1067 if (argc < 3) return -1;
1070 * Decide which filter type it is: ip, ipx, or generic
1072 type = lrad_str2int(filterType, argv[0], -1);
1073 memset(&filter, 0, sizeof(filter));
1076 * Validate the filter type.
1079 case RAD_FILTER_GENERIC:
1081 case RAD_FILTER_IPX:
1086 librad_log("Unknown Ascend filter type \"%s\"", argv[0]);
1094 token = lrad_str2int(filterKeywords, argv[1], -1);
1097 filter.direction = 1;
1101 filter.direction = 0;
1105 librad_log("Unknown Ascend filter direction \"%s\"", argv[1]);
1113 token = lrad_str2int(filterKeywords, argv[2], -1);
1115 case FILTER_FORWARD:
1124 librad_log("Unknown Ascend filter action \"%s\"", argv[2]);
1131 case RAD_FILTER_GENERIC:
1132 rcode = ascend_parse_generic(argc - 3, &argv[3],
1137 rcode = ascend_parse_ip(argc - 3, &argv[3], &filter.u.ip);
1140 case RAD_FILTER_IPX:
1141 rcode = ascend_parse_ipx(argc - 3, &argv[3], &filter.u.ipx);
1144 default: /* should never reach here. */
1149 * Touch the VP only if everything was OK.
1152 pair->length = SIZEOF_RADFILTER;
1153 memcpy(pair->strvalue, &filter, sizeof(filter));
1160 * if 'more' is set then this new entry must exist, be a
1161 * FILTER_GENERIC_TYPE, direction and disposition must match for
1162 * the previous 'more' to be valid. If any should fail then TURN OFF
1166 filt = ( RadFilter * )prevRadPair->strvalue;
1167 if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
1168 ( prevRadPair->attribute != pair->attribute ) ||
1169 ( filt->indirection != radFil.indirection ) ||
1170 ( filt->forward != radFil.forward ) ) {
1171 gen = &filt->u.generic;
1173 librad_log("filterBinary: 'more' for previous entry doesn't match: %s.\n",
1178 if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
1179 if( radFil.u.generic.more ) {
1185 memcpy( pair->strvalue, (char *) &radFil, pair->length );
1193 * Print an Ascend binary filter attribute to a string,
1194 * Grrr... Ascend makes the server do this work, instead
1195 * of doing it on the NAS.
1197 * Note we don't bother checking 'len' after the snprintf's.
1198 * This function should ONLY be called with a large (~1k) buffer.
1200 void print_abinary(VALUE_PAIR *vp, u_char *buffer, int len)
1204 ascend_filter_t filter;
1206 static const char *action[] = {"drop", "forward"};
1207 static const char *direction[] = {"out", "in"};
1212 * Just for paranoia: wrong size filters get printed as octets
1214 if (vp->length > SIZEOF_RADFILTER) {
1218 for (i = 0; i < vp->length; i++) {
1219 snprintf(p, len, "%02x", vp->strvalue[i]);
1226 memcpy(&filter, vp->strvalue, SIZEOF_RADFILTER); /* alignment issues */
1228 len -= 3; /* account for leading & trailing quotes */
1230 i = snprintf(p, len, "%s %s %s",
1231 lrad_int2str(filterType, filter.type, "??"),
1232 direction[filter.direction & 0x01],
1233 action[filter.forward & 0x01]);
1241 if (filter.type == RAD_FILTER_IP) {
1243 if (filter.u.ip.srcip) {
1244 i = snprintf(p, len, " srcip %d.%d.%d.%d/%d",
1245 ((u_char *) &filter.u.ip.srcip)[0],
1246 ((u_char *) &filter.u.ip.srcip)[1],
1247 ((u_char *) &filter.u.ip.srcip)[2],
1248 ((u_char *) &filter.u.ip.srcip)[3],
1249 filter.u.ip.srcmask);
1254 if (filter.u.ip.dstip) {
1255 i = snprintf(p, len, " dstip %d.%d.%d.%d/%d",
1256 ((u_char *) &filter.u.ip.dstip)[0],
1257 ((u_char *) &filter.u.ip.dstip)[1],
1258 ((u_char *) &filter.u.ip.dstip)[2],
1259 ((u_char *) &filter.u.ip.dstip)[3],
1260 filter.u.ip.dstmask);
1265 i = snprintf(p, len, " %s",
1266 lrad_int2str(filterProtoName, filter.u.ip.proto, "??"));
1270 if (filter.u.ip.srcPortComp > RAD_NO_COMPARE) {
1271 i = snprintf(p, len, " srcport %s %d",
1272 lrad_int2str(filterCompare, filter.u.ip.srcPortComp, "??"),
1273 ntohs(filter.u.ip.srcport));
1278 if (filter.u.ip.dstPortComp > RAD_NO_COMPARE) {
1279 i = snprintf(p, len, " dstport %s %d",
1280 lrad_int2str(filterCompare, filter.u.ip.dstPortComp, "??"),
1281 ntohs(filter.u.ip.dstport));
1286 if (filter.u.ip.established) {
1287 i = snprintf(p, len, " est");
1293 * Handle IPX filters
1295 } else if (filter.type == RAD_FILTER_IPX) {
1296 /* print for source */
1297 if (filter.u.ipx.src.net) {
1298 i = snprintf(p, len, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
1299 (unsigned int)ntohl(filter.u.ipx.src.net),
1300 filter.u.ipx.src.node[0], filter.u.ipx.src.node[1],
1301 filter.u.ipx.src.node[2], filter.u.ipx.src.node[3],
1302 filter.u.ipx.src.node[4], filter.u.ipx.src.node[5]);
1306 if (filter.u.ipx.srcSocComp > RAD_NO_COMPARE) {
1307 i = snprintf(p, len, " srcipxsock %s 0x%04x",
1308 lrad_int2str(filterCompare, filter.u.ipx.srcSocComp, "??"),
1309 ntohs(filter.u.ipx.src.socket));
1315 /* same for destination */
1316 if (filter.u.ipx.dst.net) {
1317 i = snprintf(p, len, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
1318 (unsigned int)ntohl(filter.u.ipx.dst.net),
1319 filter.u.ipx.dst.node[0], filter.u.ipx.dst.node[1],
1320 filter.u.ipx.dst.node[2], filter.u.ipx.dst.node[3],
1321 filter.u.ipx.dst.node[4], filter.u.ipx.dst.node[5]);
1325 if (filter.u.ipx.dstSocComp > RAD_NO_COMPARE) {
1326 i = snprintf(p, len, " dstipxsock %s 0x%04x",
1327 lrad_int2str(filterCompare, filter.u.ipx.dstSocComp, "??"),
1328 ntohs(filter.u.ipx.dst.socket));
1335 } else if (filter.type == RAD_FILTER_GENERIC) {
1338 i = snprintf(p, len, " %u ", (unsigned int) ntohs(filter.u.generic.offset));
1343 for (count = 0; count < ntohs(filter.u.generic.len); count++) {
1344 i = snprintf(p, len, "%02x", filter.u.generic.mask[count]);
1353 /* show the value */
1354 for (count = 0; count < ntohs(filter.u.generic.len); count++) {
1355 i = snprintf(p, len, "%02x", filter.u.generic.value[count]);
1360 i = snprintf(p, len, " %s", (filter.u.generic.compNeq) ? "!=" : "==");
1364 if (filter.u.generic.more != 0) {
1365 i = snprintf(p, len, " more");