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,2006 The FreeRADIUS server project
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/libradius.h>
32 * Two types of filters are supported, GENERIC and IP. The identifiers
36 #define RAD_FILTER_GENERIC 0
37 #define RAD_FILTER_IP 1
38 #define RAD_FILTER_IPX 2
41 * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
42 * starting at some offset. The length is:
44 #define RAD_MAX_FILTER_LEN 6
47 * ASCEND extensions for ABINARY filters
50 #define IPX_NODE_ADDR_LEN 6
52 #if ! defined( FALSE )
54 # define TRUE (! FALSE)
61 * The binary format of an IP filter. ALL fields are stored in
64 * srcip: The source IP address.
66 * dstip: The destination IP address.
68 * srcmask: The number of leading one bits in the source address
69 * mask. Specifies the bits of interest.
71 * dstmask: The number of leading one bits in the destination
72 * address mask. Specifies the bits of interest.
74 * proto: The IP protocol number
76 * established: A boolean value. TRUE when we care about the
77 * established state of a TCP connection. FALSE when
80 * srcport: TCP or UDP source port number.
82 * dstport: TCP or UDP destination port number.
84 * srcPortCmp: One of the values of the RadFilterComparison
85 * enumeration, specifying how to compare the
88 * dstPortCmp: One of the values of the RadFilterComparison
89 * enumeration, specifying how to compare the
92 * fill: Round things out to a int16_t boundary.
94 typedef struct ascend_ip_filter_t {
105 unsigned char fill[4]; /* used to be fill[2] */
106 } ascend_ip_filter_t;
112 * net: IPX Net address
114 * node: IPX Node address
116 * socket: IPX socket address
118 typedef struct ascend_ipx_net_t {
120 uint8_t node[IPX_NODE_ADDR_LEN];
125 * ascend_ipx_filter_t
127 * The binary format of an IPX filter. ALL fields are stored in
128 * network byte order.
130 * src: Source net, node, and socket.
132 * dst: Destination net, node, and socket.
134 * srcSocComp: Source socket compare value
136 * dstSocComp: Destination socket compare value
138 typedef struct ascend_ipx_filter_t {
139 ascend_ipx_net_t src;
140 ascend_ipx_net_t dst;
143 } ascend_ipx_filter_t;
147 * ascend_generic_filter_t
149 * The binary format of a GENERIC filter. ALL fields are stored in
150 * network byte order.
152 * offset: Number of bytes into packet to start comparison.
154 * len: Number of bytes to mask and compare. May not
155 * exceed RAD_MAX_FILTER_LEN.
157 * more: Boolean. If non-zero the next filter entry is
158 * also to be applied to a packet.
160 * mask: A bit mask specifying the bits to compare.
162 * value: A value to compare against the masked bits at
163 * offset in a users packet.
165 * compNeq: Defines type of comarison (Equal or Notequal)
168 * fill: Round things out to a dword boundary
170 typedef struct ascend_generic_filter_t {
174 uint8_t mask[ RAD_MAX_FILTER_LEN ];
175 uint8_t value[ RAD_MAX_FILTER_LEN ];
177 uint8_t fill[3]; /* used to be fill[1] */
178 } ascend_generic_filter_t;
183 * A binary filter element. Contains one of ascend_ip_filter_t,
184 * ascend_ipx_filter_t, or ascend_generic_filter_t.
186 * All fields are stored in network byte order.
188 * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
190 * forward: TRUE if we should forward packets that match this
191 * filter, FALSE if we should drop packets that match
194 * direction: TRUE if this is an input filter, FALSE if this is
197 * fill: Round things out to a dword boundary.
200 * ip: An ip filter entry
201 * generic: A generic filter entry
203 typedef struct ascend_filter_t {
209 ascend_ip_filter_t ip;
210 ascend_ipx_filter_t ipx;
211 ascend_generic_filter_t generic;
212 uint8_t data[28]; /* ensure it's 32 bytes */
217 * This is a wild C hack...
219 typedef struct _cpp_hack {
220 char data[(sizeof(ascend_filter_t) == 32) ? 1 : -1 ];
226 * Ascii names of some well known tcp/udp services.
227 * Used for filtering on a port type.
229 * ??? What the heck is wrong with getservbyname?
231 static const FR_NAME_NUMBER filterPortType[] = {
236 { "nameserver", 42 },
253 static const FR_NAME_NUMBER filterType[] = {
254 { "generic", RAD_FILTER_GENERIC},
255 { "ip", RAD_FILTER_IP},
256 { "ipx", RAD_FILTER_IPX},
267 FILTER_GENERIC_OFFSET,
269 FILTER_GENERIC_VALUE,
270 FILTER_GENERIC_COMPNEQ,
271 FILTER_GENERIC_COMPEQ,
280 FILTER_IPX_DST_IPXNET,
281 FILTER_IPX_DST_IPXNODE,
282 FILTER_IPX_DST_IPXSOCK,
283 FILTER_IPX_SRC_IPXNET,
284 FILTER_IPX_SRC_IPXNODE,
285 FILTER_IPX_SRC_IPXSOCK
289 static const FR_NAME_NUMBER filterKeywords[] = {
290 { "ip", FILTER_IP_TYPE },
291 { "generic", FILTER_GENERIC_TYPE },
293 { "out", FILTER_OUT },
294 { "forward", FILTER_FORWARD },
295 { "drop", FILTER_DROP },
296 { "dstip", FILTER_IP_DST },
297 { "srcip", FILTER_IP_SRC },
298 { "dstport", FILTER_IP_DST_PORT },
299 { "srcport", FILTER_IP_SRC_PORT },
300 { "est", FILTER_EST },
301 { "more", FILTER_MORE },
302 { "!=", FILTER_GENERIC_COMPNEQ },
303 { "==", FILTER_GENERIC_COMPEQ },
304 { "ipx", FILTER_IPX_TYPE },
305 { "dstipxnet", FILTER_IPX_DST_IPXNET },
306 { "dstipxnode", FILTER_IPX_DST_IPXNODE },
307 { "dstipxsock", FILTER_IPX_DST_IPXSOCK },
308 { "srcipxnet", FILTER_IPX_SRC_IPXNET },
309 { "srcipxnode", FILTER_IPX_SRC_IPXNODE },
310 { "srcipxsock", FILTER_IPX_SRC_IPXSOCK },
317 * Ascii name of protocols used for filtering.
319 * ??? What the heck is wrong with getprotobyname?
321 static const FR_NAME_NUMBER filterProtoName[] = {
332 * RadFilterComparison:
334 * An enumerated values for the IP filter port comparisons.
341 RAD_COMPARE_NOT_EQUAL
342 } RadFilterComparison;
344 static const FR_NAME_NUMBER filterCompare[] = {
345 { "<", RAD_COMPARE_LESS },
346 { "=", RAD_COMPARE_EQUAL },
347 { ">", RAD_COMPARE_GREATER },
348 { "!=", RAD_COMPARE_NOT_EQUAL },
354 * String split routine. Splits an input string IN PLACE
355 * into pieces, based on spaces.
357 static int str2argv(char *str, char **argv, int max_argc)
362 if (argc >= max_argc) return argc;
364 while (*str == ' ') *(str++) = '\0';
366 if (!*str) return argc;
371 while (*str && (*str != ' ')) str++;
379 * ascend_parse_ipx_net
381 * srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]
383 static int ascend_parse_ipx_net(int argc, char **argv,
384 ascend_ipx_net_t *net, uint8_t *comp)
389 if (argc < 3) return -1;
392 * Parse the net, which is a hex number.
394 net->net = htonl(strtol(argv[0], NULL, 16));
399 token = fr_str2int(filterKeywords, argv[1], -1);
401 case FILTER_IPX_SRC_IPXNODE:
402 case FILTER_IPX_DST_IPXNODE:
410 * Can have a leading "0x" or "0X"
413 if ((memcmp(p, "0X", 2) == 0) ||
414 (memcmp(p, "0x", 2) == 0)) p += 2;
417 * Node must be 6 octets long.
419 token = fr_hex2bin(p, net->node, IPX_NODE_ADDR_LEN);
420 if (token != IPX_NODE_ADDR_LEN) return -1;
425 if (argc == 3) return 3;
428 * Can't be too little or too much.
430 if (argc != 6) return -1;
435 token = fr_str2int(filterKeywords, argv[3], -1);
437 case FILTER_IPX_SRC_IPXSOCK:
438 case FILTER_IPX_DST_IPXSOCK:
446 * Parse the command "<", ">", "=" or "!="
448 token = fr_str2int(filterCompare, argv[4], -1);
450 case RAD_COMPARE_LESS:
451 case RAD_COMPARE_EQUAL:
452 case RAD_COMPARE_GREATER:
453 case RAD_COMPARE_NOT_EQUAL:
464 token = strtoul(argv[5], NULL, 16);
465 if (token > 65535) return -1;
468 net->socket = htons(net->socket);
472 * Everything's OK, we parsed 6 entries.
478 * ascend_parse_ipx_filter
480 * This routine parses an IPX filter string from a string.
481 * The format of the string is:
483 * [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
484 * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
486 * Fields in [...] are optional.
489 * srcipxnet: Keyword for source IPX address.
490 * nnnn = IPX Node address.
492 * srcipxnode: Keyword for source IPX Node address.
493 * mmmmm = IPX Node Address, could be FFFFFF.
494 * A vlid ipx node number should accompany ipx net number.
496 * srcipxsoc: Keyword for source IPX socket address.
498 * cmd: One of ">" or "<" or "=" or "!=".
500 * value: Socket value to be compared against, in hex.
502 * dstipxnet: Keyword for destination IPX address.
503 * nnnn = IPX Node address.
505 * dstipxnode: Keyword for destination IPX Node address.
506 * mmmmm = IPX Node Address, could be FFFFFF.
507 * A valid ipx node number should accompany ipx net number.
509 * dstipxsoc: Keyword for destination IPX socket address.
511 * cmd: One of ">" or "<" or "=" or "!=".
513 * value: Socket value to be compared against, in hex.
515 static int ascend_parse_ipx(int argc, char **argv, ascend_ipx_filter_t *filter)
522 * We may have nothing, in which case we simply return.
524 if (argc == 0) return 0;
527 * Must have "net N node M"
529 if (argc < 4) return -1;
531 while ((argc > 0) && (flags != 0x03)) {
532 token = fr_str2int(filterKeywords, argv[0], -1);
534 case FILTER_IPX_SRC_IPXNET:
535 if (flags & 0x01) return -1;
536 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
538 &(filter->srcSocComp));
539 if (rcode < 0) return -1;
545 case FILTER_IPX_DST_IPXNET:
546 if (flags & 0x02) return -1;
547 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
549 &(filter->dstSocComp));
550 if (rcode < 0) return -1;
557 fr_strerror_printf("Unknown string \"%s\" in IPX data filter",
564 * Arguments left over: die.
566 if (argc != 0) return -1;
576 * Parse an IP address and optionally a netmask, to a uint32_t.
578 * ipaddr should already be initialized to zero.
579 * ipaddr is in network byte order.
581 * Returns -1 on error, or the number of bits in the netmask, otherwise.
583 static int ascend_parse_ipaddr(uint32_t *ipaddr, char *str)
588 uint32_t netmask = 0;
594 while (*str && (count < 4) && (netmask == 0)) {
600 case '0': case '1': case '2': case '3':
601 case '4': case '5': case '6': case '7':
604 ip[count] += (*str) - '0';
609 case '.': /* dot between IP numbers. */
611 if (ip[count] > 255) return -1;
614 * 24, 16, 8, 0, done.
616 *ipaddr |= (ip[count] << (8 * (3 - count)));
620 case '/': /* netmask */
623 if ((masklen < 0) || (masklen > 32)) return -1;
624 str += strspn(str, "0123456789");
630 fr_strerror_printf("Invalid character in IP address");
633 } /* loop over one character */
634 } /* loop until the count hits 4 */
639 * Do the last one, too.
641 if (ip[count] > 255) return -1;
644 * 24, 16, 8, 0, done.
646 *ipaddr |= (ip[count] << (8 * (3 - count)));
650 * We've hit the end of the IP address, and there's something
651 * else left over: die.
656 * Set the default netmask.
661 } else if ((*ipaddr & 0x80000000) == 0) {
663 } else if ((*ipaddr & 0xc0000000) == 0x80000000) {
665 } else if ((*ipaddr & 0xe0000000) == 0xc0000000) {
672 *ipaddr = htonl(*ipaddr);
677 * ascend_parse_port: Parse a comparator and port.
679 * Returns -1 on error, or the comparator.
681 static int ascend_parse_port(uint16_t *port, char *compare, char *str)
683 int rcode, token = -1;
686 * There MUST be a comparison string.
688 rcode = fr_str2int(filterCompare, compare, -1);
689 if (rcode < 0) return rcode;
691 if (strspn(str, "0123456789") == strlen(str)) {
694 token = fr_str2int(filterPortType, str, -1);
697 if ((token < 0) || (token > 65535)) return -1;
700 *port = htons(*port);
706 #define IP_SRC_ADDR_FLAG (1 << 0)
707 #define IP_DEST_ADDR_FLAG (1 << 1)
708 #define IP_SRC_PORT_FLAG (1 << 2)
709 #define IP_DEST_PORT_FLAG (1 << 3)
710 #define IP_PROTO_FLAG (1 << 4)
711 #define IP_EST_FLAG (1 << 5)
713 #define DONE_FLAGS (IP_SRC_ADDR_FLAG | IP_DEST_ADDR_FLAG | \
714 IP_SRC_PORT_FLAG | IP_DEST_PORT_FLAG | \
715 IP_PROTO_FLAG | IP_EST_FLAG)
720 * This routine parses an IP filter string from a RADIUS
721 * reply. The format of the string is:
723 * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
724 * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ]
726 * Fields in [...] are optional.
728 * dstip: Keyword for destination IP address.
729 * n.n.n.n = IP address. /nn - netmask.
731 * srcip: Keyword for source IP address.
732 * n.n.n.n = IP address. /nn - netmask.
734 * proto: Optional protocol field. Either a name or
735 * number. Known names are in FilterProtoName[].
737 * dstport: Keyword for destination port. Only valid with tcp
738 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
741 * srcport: Keyword for source port. Only valid with tcp
742 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
745 * est: Keyword for TCP established. Valid only for tcp.
748 static int ascend_parse_ip(int argc, char **argv, ascend_ip_filter_t *filter)
755 * We may have nothing, in which case we simply return.
757 if (argc == 0) return 0;
760 * There may, or may not, be src & dst IP's in the string.
763 while ((argc > 0) && (flags != DONE_FLAGS)) {
764 token = fr_str2int(filterKeywords, argv[0], -1);
767 if (flags & IP_SRC_ADDR_FLAG) return -1;
768 if (argc < 2) return -1;
770 rcode = ascend_parse_ipaddr(&filter->srcip, argv[1]);
771 if (rcode < 0) return rcode;
773 filter->srcmask = rcode;
774 flags |= IP_SRC_ADDR_FLAG;
780 if (flags & IP_DEST_ADDR_FLAG) return -1;
781 if (argc < 2) return -1;
783 rcode = ascend_parse_ipaddr(&filter->dstip, argv[1]);
784 if (rcode < 0) return rcode;
786 filter->dstmask = rcode;
787 flags |= IP_DEST_ADDR_FLAG;
792 case FILTER_IP_SRC_PORT:
793 if (flags & IP_SRC_PORT_FLAG) return -1;
794 if (argc < 3) return -1;
796 rcode = ascend_parse_port(&filter->srcport,
798 if (rcode < 0) return rcode;
799 filter->srcPortComp = rcode;
801 flags |= IP_SRC_PORT_FLAG;
806 case FILTER_IP_DST_PORT:
807 if (flags & IP_DEST_PORT_FLAG) return -1;
808 if (argc < 3) return -1;
810 rcode = ascend_parse_port(&filter->dstport,
812 if (rcode < 0) return rcode;
813 filter->dstPortComp = rcode;
815 flags |= IP_DEST_PORT_FLAG;
821 if (flags & IP_EST_FLAG) return -1;
822 filter->established = 1;
825 flags |= IP_EST_FLAG;
829 if (flags & IP_PROTO_FLAG) return -1;
830 if (strspn(argv[0], "0123456789") == strlen(argv[0])) {
831 token = atoi(argv[0]);
833 token = fr_str2int(filterProtoName, argv[0], -1);
835 fr_strerror_printf("Unknown IP protocol \"%s\" in IP data filter",
840 filter->proto = token;
841 flags |= IP_PROTO_FLAG;
850 * We should have parsed everything by now.
853 fr_strerror_printf("Unknown extra string \"%s\" in IP data filter",
863 * ascend_parse_generic
865 * This routine parses a Generic filter string from a RADIUS
866 * reply. The format of the string is:
868 * generic dir action offset mask value [== or != ] [more]
870 * Fields in [...] are optional.
872 * offset: A Number. Specifies an offset into a frame
873 * to start comparing.
875 * mask: A hexadecimal mask of bits to compare.
877 * value: A value to compare with the masked data.
879 * compNeq: Defines type of comparison. ( "==" or "!=")
882 * more: Optional keyword MORE, to represent the attachment
885 static int ascend_parse_generic(int argc, char **argv,
886 ascend_generic_filter_t *filter)
893 * We may have nothing, in which case we simply return.
895 if (argc == 0) return 0;
898 * We need at least "offset mask value"
900 if (argc < 3) return -1;
903 * No more than optional comparison and "more"
905 if (argc > 5) return -1;
908 * Offset is a uint16_t number.
910 if (strspn(argv[0], "0123456789") != strlen(argv[0])) return -1;
912 rcode = atoi(argv[0]);
913 if (rcode > 65535) return -1;
915 filter->offset = rcode;
916 filter->offset = htons(filter->offset);
918 rcode = fr_hex2bin(argv[1], filter->mask, sizeof(filter->mask));
919 if (rcode != sizeof(filter->mask)) return -1;
921 token = fr_hex2bin(argv[2], filter->value, sizeof(filter->value));
922 if (token != sizeof(filter->value)) return -1;
925 * The mask and value MUST be the same length.
927 if (rcode != token) return -1;
930 filter->len = htons(filter->len);
933 * Nothing more. Exit.
935 if (argc == 3) return 0;
942 token = fr_str2int(filterKeywords, argv[0], -1);
944 case FILTER_GENERIC_COMPNEQ:
945 if (flags & 0x01) return -1;
946 filter->compNeq = TRUE;
949 case FILTER_GENERIC_COMPEQ:
950 if (flags & 0x01) return -1;
951 filter->compNeq = FALSE;
956 if (flags & 0x02) return -1;
957 filter->more = htons( 1 );
962 fr_strerror_printf("Invalid string \"%s\" in generic data filter",
978 * This routine will call routines to parse entries from an ASCII format
979 * to a binary format recognized by the Ascend boxes.
981 * pair: Pointer to value_pair to place return.
983 * valstr: The string to parse
985 * return: -1 for error or 0.
988 ascend_parse_filter(VALUE_PAIR *pair)
994 ascend_filter_t filter;
999 * Rather than printing specific error messages, we create
1000 * a general one here, which won't be used if the function
1003 fr_strerror_printf("Text is not in proper format");
1006 * Tokenize the input string in the VP.
1008 * Once the filter is *completelty* parsed, then we will
1009 * over-write it with the final binary filter.
1011 argc = str2argv(pair->vp_strvalue, argv, 32);
1012 if (argc < 3) return -1;
1015 * Decide which filter type it is: ip, ipx, or generic
1017 type = fr_str2int(filterType, argv[0], -1);
1018 memset(&filter, 0, sizeof(filter));
1021 * Validate the filter type.
1024 case RAD_FILTER_GENERIC:
1026 case RAD_FILTER_IPX:
1031 fr_strerror_printf("Unknown Ascend filter type \"%s\"", argv[0]);
1039 token = fr_str2int(filterKeywords, argv[1], -1);
1042 filter.direction = 1;
1046 filter.direction = 0;
1050 fr_strerror_printf("Unknown Ascend filter direction \"%s\"", argv[1]);
1058 token = fr_str2int(filterKeywords, argv[2], -1);
1060 case FILTER_FORWARD:
1069 fr_strerror_printf("Unknown Ascend filter action \"%s\"", argv[2]);
1076 case RAD_FILTER_GENERIC:
1077 rcode = ascend_parse_generic(argc - 3, &argv[3],
1082 rcode = ascend_parse_ip(argc - 3, &argv[3], &filter.u.ip);
1085 case RAD_FILTER_IPX:
1086 rcode = ascend_parse_ipx(argc - 3, &argv[3], &filter.u.ipx);
1089 default: /* should never reach here. */
1094 * Touch the VP only if everything was OK.
1097 pair->length = sizeof(filter);
1098 memcpy(pair->vp_filter, &filter, sizeof(filter));
1105 * if 'more' is set then this new entry must exist, be a
1106 * FILTER_GENERIC_TYPE, direction and disposition must match for
1107 * the previous 'more' to be valid. If any should fail then TURN OFF
1111 filt = ( RadFilter * )prevRadPair->vp_strvalue;
1112 if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
1113 ( prevRadPair->attribute != pair->attribute ) ||
1114 ( filt->indirection != radFil.indirection ) ||
1115 ( filt->forward != radFil.forward ) ) {
1116 gen = &filt->u.generic;
1118 fr_strerror_printf("filterBinary: 'more' for previous entry doesn't match: %s.\n",
1123 if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
1124 if( radFil.u.generic.more ) {
1130 memcpy( pair->vp_strvalue, &radFil, pair->length );
1138 * Print an Ascend binary filter attribute to a string,
1139 * Grrr... Ascend makes the server do this work, instead
1140 * of doing it on the NAS.
1142 * Note we don't bother checking 'len' after the snprintf's.
1143 * This function should ONLY be called with a large (~1k) buffer.
1145 void print_abinary(VALUE_PAIR *vp, char *buffer, size_t len)
1149 ascend_filter_t *filter;
1151 static const char *action[] = {"drop", "forward"};
1152 static const char *direction[] = {"out", "in"};
1157 * Just for paranoia: wrong size filters get printed as octets
1159 if (vp->length != sizeof(*filter)) {
1163 for (i = 0; i < vp->length; i++) {
1164 snprintf(p, len, "%02x", vp->vp_octets[i]);
1172 len -= 3; /* account for leading & trailing quotes */
1174 filter = (ascend_filter_t *) &(vp->vp_filter);
1175 i = snprintf(p, len, "%s %s %s",
1176 fr_int2str(filterType, filter->type, "??"),
1177 direction[filter->direction & 0x01],
1178 action[filter->forward & 0x01]);
1186 if (filter->type == RAD_FILTER_IP) {
1188 if (filter->u.ip.srcip) {
1189 i = snprintf(p, len, " srcip %d.%d.%d.%d/%d",
1190 ((uint8_t *) &filter->u.ip.srcip)[0],
1191 ((uint8_t *) &filter->u.ip.srcip)[1],
1192 ((uint8_t *) &filter->u.ip.srcip)[2],
1193 ((uint8_t *) &filter->u.ip.srcip)[3],
1194 filter->u.ip.srcmask);
1199 if (filter->u.ip.dstip) {
1200 i = snprintf(p, len, " dstip %d.%d.%d.%d/%d",
1201 ((uint8_t *) &filter->u.ip.dstip)[0],
1202 ((uint8_t *) &filter->u.ip.dstip)[1],
1203 ((uint8_t *) &filter->u.ip.dstip)[2],
1204 ((uint8_t *) &filter->u.ip.dstip)[3],
1205 filter->u.ip.dstmask);
1210 i = snprintf(p, len, " %s",
1211 fr_int2str(filterProtoName, filter->u.ip.proto, "??"));
1215 if (filter->u.ip.srcPortComp > RAD_NO_COMPARE) {
1216 i = snprintf(p, len, " srcport %s %d",
1217 fr_int2str(filterCompare, filter->u.ip.srcPortComp, "??"),
1218 ntohs(filter->u.ip.srcport));
1223 if (filter->u.ip.dstPortComp > RAD_NO_COMPARE) {
1224 i = snprintf(p, len, " dstport %s %d",
1225 fr_int2str(filterCompare, filter->u.ip.dstPortComp, "??"),
1226 ntohs(filter->u.ip.dstport));
1231 if (filter->u.ip.established) {
1232 i = snprintf(p, len, " est");
1238 * Handle IPX filters
1240 } else if (filter->type == RAD_FILTER_IPX) {
1241 /* print for source */
1242 if (filter->u.ipx.src.net) {
1243 i = snprintf(p, len, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
1244 (unsigned int)ntohl(filter->u.ipx.src.net),
1245 filter->u.ipx.src.node[0], filter->u.ipx.src.node[1],
1246 filter->u.ipx.src.node[2], filter->u.ipx.src.node[3],
1247 filter->u.ipx.src.node[4], filter->u.ipx.src.node[5]);
1251 if (filter->u.ipx.srcSocComp > RAD_NO_COMPARE) {
1252 i = snprintf(p, len, " srcipxsock %s 0x%04x",
1253 fr_int2str(filterCompare, filter->u.ipx.srcSocComp, "??"),
1254 ntohs(filter->u.ipx.src.socket));
1260 /* same for destination */
1261 if (filter->u.ipx.dst.net) {
1262 i = snprintf(p, len, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
1263 (unsigned int)ntohl(filter->u.ipx.dst.net),
1264 filter->u.ipx.dst.node[0], filter->u.ipx.dst.node[1],
1265 filter->u.ipx.dst.node[2], filter->u.ipx.dst.node[3],
1266 filter->u.ipx.dst.node[4], filter->u.ipx.dst.node[5]);
1270 if (filter->u.ipx.dstSocComp > RAD_NO_COMPARE) {
1271 i = snprintf(p, len, " dstipxsock %s 0x%04x",
1272 fr_int2str(filterCompare, filter->u.ipx.dstSocComp, "??"),
1273 ntohs(filter->u.ipx.dst.socket));
1280 } else if (filter->type == RAD_FILTER_GENERIC) {
1283 i = snprintf(p, len, " %u ", (unsigned int) ntohs(filter->u.generic.offset));
1288 for (count = 0; count < ntohs(filter->u.generic.len); count++) {
1289 i = snprintf(p, len, "%02x", filter->u.generic.mask[count]);
1298 /* show the value */
1299 for (count = 0; count < ntohs(filter->u.generic.len); count++) {
1300 i = snprintf(p, len, "%02x", filter->u.generic.value[count]);
1305 i = snprintf(p, len, " %s", (filter->u.generic.compNeq) ? "!=" : "==");
1309 if (filter->u.generic.more != 0) {
1310 i = snprintf(p, len, " more");