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>
28 #ifdef WITH_ASCEND_BINARY
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 * ascend_parse_ipx_net
356 * srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]
358 static int ascend_parse_ipx_net(int argc, char **argv,
359 ascend_ipx_net_t *net, uint8_t *comp)
364 if (argc < 3) return -1;
367 * Parse the net, which is a hex number.
369 net->net = htonl(strtol(argv[0], NULL, 16));
374 token = fr_str2int(filterKeywords, argv[1], -1);
376 case FILTER_IPX_SRC_IPXNODE:
377 case FILTER_IPX_DST_IPXNODE:
385 * Can have a leading "0x" or "0X"
388 if ((memcmp(p, "0X", 2) == 0) ||
389 (memcmp(p, "0x", 2) == 0)) p += 2;
392 * Node must be 6 octets long.
394 token = fr_hex2bin(p, net->node, IPX_NODE_ADDR_LEN);
395 if (token != IPX_NODE_ADDR_LEN) return -1;
400 if (argc == 3) return 3;
403 * Can't be too little or too much.
405 if (argc != 6) return -1;
410 token = fr_str2int(filterKeywords, argv[3], -1);
412 case FILTER_IPX_SRC_IPXSOCK:
413 case FILTER_IPX_DST_IPXSOCK:
421 * Parse the command "<", ">", "=" or "!="
423 token = fr_str2int(filterCompare, argv[4], -1);
425 case RAD_COMPARE_LESS:
426 case RAD_COMPARE_EQUAL:
427 case RAD_COMPARE_GREATER:
428 case RAD_COMPARE_NOT_EQUAL:
439 token = strtoul(argv[5], NULL, 16);
440 if (token > 65535) return -1;
443 net->socket = htons(net->socket);
447 * Everything's OK, we parsed 6 entries.
453 * ascend_parse_ipx_filter
455 * This routine parses an IPX filter string from a string.
456 * The format of the string is:
458 * [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
459 * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
461 * Fields in [...] are optional.
464 * srcipxnet: Keyword for source IPX address.
465 * nnnn = IPX Node address.
467 * srcipxnode: Keyword for source IPX Node address.
468 * mmmmm = IPX Node Address, could be FFFFFF.
469 * A vlid ipx node number should accompany ipx net number.
471 * srcipxsoc: Keyword for source IPX socket address.
473 * cmd: One of ">" or "<" or "=" or "!=".
475 * value: Socket value to be compared against, in hex.
477 * dstipxnet: Keyword for destination IPX address.
478 * nnnn = IPX Node address.
480 * dstipxnode: Keyword for destination IPX Node address.
481 * mmmmm = IPX Node Address, could be FFFFFF.
482 * A valid ipx node number should accompany ipx net number.
484 * dstipxsoc: Keyword for destination IPX socket address.
486 * cmd: One of ">" or "<" or "=" or "!=".
488 * value: Socket value to be compared against, in hex.
490 static int ascend_parse_ipx(int argc, char **argv, ascend_ipx_filter_t *filter)
497 * We may have nothing, in which case we simply return.
499 if (argc == 0) return 0;
502 * Must have "net N node M"
504 if (argc < 4) return -1;
506 while ((argc > 0) && (flags != 0x03)) {
507 token = fr_str2int(filterKeywords, argv[0], -1);
509 case FILTER_IPX_SRC_IPXNET:
510 if (flags & 0x01) return -1;
511 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
513 &(filter->srcSocComp));
514 if (rcode < 0) return -1;
520 case FILTER_IPX_DST_IPXNET:
521 if (flags & 0x02) return -1;
522 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
524 &(filter->dstSocComp));
525 if (rcode < 0) return -1;
532 fr_strerror_printf("Unknown string \"%s\" in IPX data filter",
539 * Arguments left over: die.
541 if (argc != 0) return -1;
551 * Parse an IP address and optionally a netmask, to a uint32_t.
553 * ipaddr should already be initialized to zero.
554 * ipaddr is in network byte order.
556 * Returns -1 on error, or the number of bits in the netmask, otherwise.
558 static int ascend_parse_ipaddr(uint32_t *ipaddr, char *str)
563 uint32_t netmask = 0;
569 while (*str && (count < 4) && (netmask == 0)) {
575 case '0': case '1': case '2': case '3':
576 case '4': case '5': case '6': case '7':
579 ip[count] += (*str) - '0';
584 case '.': /* dot between IP numbers. */
586 if (ip[count] > 255) return -1;
589 * 24, 16, 8, 0, done.
591 *ipaddr |= (ip[count] << (8 * (3 - count)));
595 case '/': /* netmask */
598 if ((masklen < 0) || (masklen > 32)) return -1;
599 str += strspn(str, "0123456789");
605 fr_strerror_printf("Invalid character in IP address");
608 } /* loop over one character */
609 } /* loop until the count hits 4 */
614 * Do the last one, too.
616 if (ip[count] > 255) return -1;
619 * 24, 16, 8, 0, done.
621 *ipaddr |= (ip[count] << (8 * (3 - count)));
625 * We've hit the end of the IP address, and there's something
626 * else left over: die.
631 * Set the default netmask.
636 } else if ((*ipaddr & 0x80000000) == 0) {
638 } else if ((*ipaddr & 0xc0000000) == 0x80000000) {
640 } else if ((*ipaddr & 0xe0000000) == 0xc0000000) {
647 *ipaddr = htonl(*ipaddr);
652 * ascend_parse_port: Parse a comparator and port.
654 * Returns -1 on error, or the comparator.
656 static int ascend_parse_port(uint16_t *port, char *compare, char *str)
658 int rcode, token = -1;
661 * There MUST be a comparison string.
663 rcode = fr_str2int(filterCompare, compare, -1);
664 if (rcode < 0) return rcode;
666 if (strspn(str, "0123456789") == strlen(str)) {
669 token = fr_str2int(filterPortType, str, -1);
672 if ((token < 0) || (token > 65535)) return -1;
675 *port = htons(*port);
681 #define IP_SRC_ADDR_FLAG (1 << 0)
682 #define IP_DEST_ADDR_FLAG (1 << 1)
683 #define IP_SRC_PORT_FLAG (1 << 2)
684 #define IP_DEST_PORT_FLAG (1 << 3)
685 #define IP_PROTO_FLAG (1 << 4)
686 #define IP_EST_FLAG (1 << 5)
688 #define DONE_FLAGS (IP_SRC_ADDR_FLAG | IP_DEST_ADDR_FLAG | \
689 IP_SRC_PORT_FLAG | IP_DEST_PORT_FLAG | \
690 IP_PROTO_FLAG | IP_EST_FLAG)
695 * This routine parses an IP filter string from a RADIUS
696 * reply. The format of the string is:
698 * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
699 * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ]
701 * Fields in [...] are optional.
703 * dstip: Keyword for destination IP address.
704 * n.n.n.n = IP address. /nn - netmask.
706 * srcip: Keyword for source IP address.
707 * n.n.n.n = IP address. /nn - netmask.
709 * proto: Optional protocol field. Either a name or
710 * number. Known names are in FilterProtoName[].
712 * dstport: Keyword for destination port. Only valid with tcp
713 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
716 * srcport: Keyword for source port. Only valid with tcp
717 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
720 * est: Keyword for TCP established. Valid only for tcp.
723 static int ascend_parse_ip(int argc, char **argv, ascend_ip_filter_t *filter)
730 * We may have nothing, in which case we simply return.
732 if (argc == 0) return 0;
735 * There may, or may not, be src & dst IP's in the string.
738 while ((argc > 0) && (flags != DONE_FLAGS)) {
739 token = fr_str2int(filterKeywords, argv[0], -1);
742 if (flags & IP_SRC_ADDR_FLAG) return -1;
743 if (argc < 2) return -1;
745 rcode = ascend_parse_ipaddr(&filter->srcip, argv[1]);
746 if (rcode < 0) return rcode;
748 filter->srcmask = rcode;
749 flags |= IP_SRC_ADDR_FLAG;
755 if (flags & IP_DEST_ADDR_FLAG) return -1;
756 if (argc < 2) return -1;
758 rcode = ascend_parse_ipaddr(&filter->dstip, argv[1]);
759 if (rcode < 0) return rcode;
761 filter->dstmask = rcode;
762 flags |= IP_DEST_ADDR_FLAG;
767 case FILTER_IP_SRC_PORT:
768 if (flags & IP_SRC_PORT_FLAG) return -1;
769 if (argc < 3) return -1;
771 rcode = ascend_parse_port(&filter->srcport,
773 if (rcode < 0) return rcode;
774 filter->srcPortComp = rcode;
776 flags |= IP_SRC_PORT_FLAG;
781 case FILTER_IP_DST_PORT:
782 if (flags & IP_DEST_PORT_FLAG) return -1;
783 if (argc < 3) return -1;
785 rcode = ascend_parse_port(&filter->dstport,
787 if (rcode < 0) return rcode;
788 filter->dstPortComp = rcode;
790 flags |= IP_DEST_PORT_FLAG;
796 if (flags & IP_EST_FLAG) return -1;
797 filter->established = 1;
800 flags |= IP_EST_FLAG;
804 if (flags & IP_PROTO_FLAG) return -1;
805 if (strspn(argv[0], "0123456789") == strlen(argv[0])) {
806 token = atoi(argv[0]);
808 token = fr_str2int(filterProtoName, argv[0], -1);
810 fr_strerror_printf("Unknown IP protocol \"%s\" in IP data filter",
815 filter->proto = token;
816 flags |= IP_PROTO_FLAG;
825 * We should have parsed everything by now.
828 fr_strerror_printf("Unknown extra string \"%s\" in IP data filter",
838 * ascend_parse_generic
840 * This routine parses a Generic filter string from a RADIUS
841 * reply. The format of the string is:
843 * generic dir action offset mask value [== or != ] [more]
845 * Fields in [...] are optional.
847 * offset: A Number. Specifies an offset into a frame
848 * to start comparing.
850 * mask: A hexadecimal mask of bits to compare.
852 * value: A value to compare with the masked data.
854 * compNeq: Defines type of comparison. ( "==" or "!=")
857 * more: Optional keyword MORE, to represent the attachment
860 static int ascend_parse_generic(int argc, char **argv,
861 ascend_generic_filter_t *filter)
868 * We may have nothing, in which case we simply return.
870 if (argc == 0) return 0;
873 * We need at least "offset mask value"
875 if (argc < 3) return -1;
878 * No more than optional comparison and "more"
880 if (argc > 5) return -1;
883 * Offset is a uint16_t number.
885 if (strspn(argv[0], "0123456789") != strlen(argv[0])) return -1;
887 rcode = atoi(argv[0]);
888 if (rcode > 65535) return -1;
890 filter->offset = rcode;
891 filter->offset = htons(filter->offset);
893 rcode = fr_hex2bin(argv[1], filter->mask, sizeof(filter->mask));
894 if (rcode != sizeof(filter->mask)) return -1;
896 token = fr_hex2bin(argv[2], filter->value, sizeof(filter->value));
897 if (token != sizeof(filter->value)) return -1;
900 * The mask and value MUST be the same length.
902 if (rcode != token) return -1;
905 filter->len = htons(filter->len);
908 * Nothing more. Exit.
910 if (argc == 3) return 0;
917 token = fr_str2int(filterKeywords, argv[0], -1);
919 case FILTER_GENERIC_COMPNEQ:
920 if (flags & 0x01) return -1;
921 filter->compNeq = TRUE;
924 case FILTER_GENERIC_COMPEQ:
925 if (flags & 0x01) return -1;
926 filter->compNeq = FALSE;
931 if (flags & 0x02) return -1;
932 filter->more = htons( 1 );
937 fr_strerror_printf("Invalid string \"%s\" in generic data filter",
953 * This routine will call routines to parse entries from an ASCII format
954 * to a binary format recognized by the Ascend boxes.
956 * pair: Pointer to value_pair to place return.
958 * valstr: The string to parse
960 * return: -1 for error or 0.
963 ascend_parse_filter(VALUE_PAIR *pair)
969 ascend_filter_t filter;
974 * Rather than printing specific error messages, we create
975 * a general one here, which won't be used if the function
978 fr_strerror_printf("Text is not in proper format");
981 * Tokenize the input string in the VP.
983 * Once the filter is *completelty* parsed, then we will
984 * over-write it with the final binary filter.
986 argc = str2argv(pair->vp_strvalue, argv, 32);
987 if (argc < 3) return -1;
990 * Decide which filter type it is: ip, ipx, or generic
992 type = fr_str2int(filterType, argv[0], -1);
993 memset(&filter, 0, sizeof(filter));
996 * Validate the filter type.
999 case RAD_FILTER_GENERIC:
1001 case RAD_FILTER_IPX:
1006 fr_strerror_printf("Unknown Ascend filter type \"%s\"", argv[0]);
1014 token = fr_str2int(filterKeywords, argv[1], -1);
1017 filter.direction = 1;
1021 filter.direction = 0;
1025 fr_strerror_printf("Unknown Ascend filter direction \"%s\"", argv[1]);
1033 token = fr_str2int(filterKeywords, argv[2], -1);
1035 case FILTER_FORWARD:
1044 fr_strerror_printf("Unknown Ascend filter action \"%s\"", argv[2]);
1051 case RAD_FILTER_GENERIC:
1052 rcode = ascend_parse_generic(argc - 3, &argv[3],
1057 rcode = ascend_parse_ip(argc - 3, &argv[3], &filter.u.ip);
1060 case RAD_FILTER_IPX:
1061 rcode = ascend_parse_ipx(argc - 3, &argv[3], &filter.u.ipx);
1064 default: /* should never reach here. */
1069 * Touch the VP only if everything was OK.
1072 pair->length = sizeof(filter);
1073 memcpy(pair->vp_filter, &filter, sizeof(filter));
1080 * if 'more' is set then this new entry must exist, be a
1081 * FILTER_GENERIC_TYPE, direction and disposition must match for
1082 * the previous 'more' to be valid. If any should fail then TURN OFF
1086 filt = ( RadFilter * )prevRadPair->vp_strvalue;
1087 if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
1088 ( prevRadPair->attribute != pair->attribute ) ||
1089 ( filt->indirection != radFil.indirection ) ||
1090 ( filt->forward != radFil.forward ) ) {
1091 gen = &filt->u.generic;
1093 fr_strerror_printf("filterBinary: 'more' for previous entry doesn't match: %s.\n",
1098 if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
1099 if( radFil.u.generic.more ) {
1105 memcpy( pair->vp_strvalue, &radFil, pair->length );
1113 * Print an Ascend binary filter attribute to a string,
1114 * Grrr... Ascend makes the server do this work, instead
1115 * of doing it on the NAS.
1117 * Note we don't bother checking 'len' after the snprintf's.
1118 * This function should ONLY be called with a large (~1k) buffer.
1120 void print_abinary(const VALUE_PAIR *vp, char *buffer, size_t len, int delimitst)
1124 ascend_filter_t *filter;
1126 static const char *action[] = {"drop", "forward"};
1127 static const char *direction[] = {"out", "in"};
1132 * Just for paranoia: wrong size filters get printed as octets
1134 if (vp->length != sizeof(*filter)) {
1138 for (i = 0; i < vp->length; i++) {
1139 snprintf(p, len, "%02x", vp->vp_octets[i]);
1148 len -= 3; /* account for leading & trailing quotes */
1151 filter = (ascend_filter_t *) &(vp->vp_filter);
1152 i = snprintf(p, len, "%s %s %s",
1153 fr_int2str(filterType, filter->type, "??"),
1154 direction[filter->direction & 0x01],
1155 action[filter->forward & 0x01]);
1163 if (filter->type == RAD_FILTER_IP) {
1165 if (filter->u.ip.srcip) {
1166 i = snprintf(p, len, " srcip %d.%d.%d.%d/%d",
1167 ((uint8_t *) &filter->u.ip.srcip)[0],
1168 ((uint8_t *) &filter->u.ip.srcip)[1],
1169 ((uint8_t *) &filter->u.ip.srcip)[2],
1170 ((uint8_t *) &filter->u.ip.srcip)[3],
1171 filter->u.ip.srcmask);
1176 if (filter->u.ip.dstip) {
1177 i = snprintf(p, len, " dstip %d.%d.%d.%d/%d",
1178 ((uint8_t *) &filter->u.ip.dstip)[0],
1179 ((uint8_t *) &filter->u.ip.dstip)[1],
1180 ((uint8_t *) &filter->u.ip.dstip)[2],
1181 ((uint8_t *) &filter->u.ip.dstip)[3],
1182 filter->u.ip.dstmask);
1187 i = snprintf(p, len, " %s",
1188 fr_int2str(filterProtoName, filter->u.ip.proto, "??"));
1192 if (filter->u.ip.srcPortComp > RAD_NO_COMPARE) {
1193 i = snprintf(p, len, " srcport %s %d",
1194 fr_int2str(filterCompare, filter->u.ip.srcPortComp, "??"),
1195 ntohs(filter->u.ip.srcport));
1200 if (filter->u.ip.dstPortComp > RAD_NO_COMPARE) {
1201 i = snprintf(p, len, " dstport %s %d",
1202 fr_int2str(filterCompare, filter->u.ip.dstPortComp, "??"),
1203 ntohs(filter->u.ip.dstport));
1208 if (filter->u.ip.established) {
1209 i = snprintf(p, len, " est");
1215 * Handle IPX filters
1217 } else if (filter->type == RAD_FILTER_IPX) {
1218 /* print for source */
1219 if (filter->u.ipx.src.net) {
1220 i = snprintf(p, len, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
1221 (unsigned int)ntohl(filter->u.ipx.src.net),
1222 filter->u.ipx.src.node[0], filter->u.ipx.src.node[1],
1223 filter->u.ipx.src.node[2], filter->u.ipx.src.node[3],
1224 filter->u.ipx.src.node[4], filter->u.ipx.src.node[5]);
1228 if (filter->u.ipx.srcSocComp > RAD_NO_COMPARE) {
1229 i = snprintf(p, len, " srcipxsock %s 0x%04x",
1230 fr_int2str(filterCompare, filter->u.ipx.srcSocComp, "??"),
1231 ntohs(filter->u.ipx.src.socket));
1237 /* same for destination */
1238 if (filter->u.ipx.dst.net) {
1239 i = snprintf(p, len, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
1240 (unsigned int)ntohl(filter->u.ipx.dst.net),
1241 filter->u.ipx.dst.node[0], filter->u.ipx.dst.node[1],
1242 filter->u.ipx.dst.node[2], filter->u.ipx.dst.node[3],
1243 filter->u.ipx.dst.node[4], filter->u.ipx.dst.node[5]);
1247 if (filter->u.ipx.dstSocComp > RAD_NO_COMPARE) {
1248 i = snprintf(p, len, " dstipxsock %s 0x%04x",
1249 fr_int2str(filterCompare, filter->u.ipx.dstSocComp, "??"),
1250 ntohs(filter->u.ipx.dst.socket));
1257 } else if (filter->type == RAD_FILTER_GENERIC) {
1260 i = snprintf(p, len, " %u ", (unsigned int) ntohs(filter->u.generic.offset));
1265 for (count = 0; count < ntohs(filter->u.generic.len); count++) {
1266 i = snprintf(p, len, "%02x", filter->u.generic.mask[count]);
1275 /* show the value */
1276 for (count = 0; count < ntohs(filter->u.generic.len); count++) {
1277 i = snprintf(p, len, "%02x", filter->u.generic.value[count]);
1282 i = snprintf(p, len, " %s", (filter->u.generic.compNeq) ? "!=" : "==");
1286 if (filter->u.generic.more != 0) {
1287 i = snprintf(p, len, " more");
1293 if (delimitst) *(p++) = '"';