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/autoconf.h>
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
37 #include <freeradius-devel/missing.h>
38 #include <freeradius-devel/libradius.h>
41 * Two types of filters are supported, GENERIC and IP. The identifiers
45 #define RAD_FILTER_GENERIC 0
46 #define RAD_FILTER_IP 1
47 #define RAD_FILTER_IPX 2
50 * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
51 * starting at some offset. The length is:
53 #define RAD_MAX_FILTER_LEN 6
56 * ASCEND extensions for ABINARY filters
59 #define IPX_NODE_ADDR_LEN 6
61 #if ! defined( FALSE )
63 # define TRUE (! FALSE)
70 * The binary format of an IP filter. ALL fields are stored in
73 * srcip: The source IP address.
75 * dstip: The destination IP address.
77 * srcmask: The number of leading one bits in the source address
78 * mask. Specifies the bits of interest.
80 * dstmask: The number of leading one bits in the destination
81 * address mask. Specifies the bits of interest.
83 * proto: The IP protocol number
85 * established: A boolean value. TRUE when we care about the
86 * established state of a TCP connection. FALSE when
89 * srcport: TCP or UDP source port number.
91 * dstport: TCP or UDP destination port number.
93 * srcPortCmp: One of the values of the RadFilterComparison
94 * enumeration, specifying how to compare the
97 * dstPortCmp: One of the values of the RadFilterComparison
98 * enumeration, specifying how to compare the
101 * fill: Round things out to a int16_t boundary.
103 typedef struct ascend_ip_filter_t {
114 unsigned char fill[4]; /* used to be fill[2] */
115 } ascend_ip_filter_t;
121 * net: IPX Net address
123 * node: IPX Node address
125 * socket: IPX socket address
127 typedef struct ascend_ipx_net_t {
129 uint8_t node[IPX_NODE_ADDR_LEN];
134 * ascend_ipx_filter_t
136 * The binary format of an IPX filter. ALL fields are stored in
137 * network byte order.
139 * src: Source net, node, and socket.
141 * dst: Destination net, node, and socket.
143 * srcSocComp: Source socket compare value
145 * dstSocComp: Destination socket compare value
147 typedef struct ascend_ipx_filter_t {
148 ascend_ipx_net_t src;
149 ascend_ipx_net_t dst;
152 } ascend_ipx_filter_t;
156 * ascend_generic_filter_t
158 * The binary format of a GENERIC filter. ALL fields are stored in
159 * network byte order.
161 * offset: Number of bytes into packet to start comparison.
163 * len: Number of bytes to mask and compare. May not
164 * exceed RAD_MAX_FILTER_LEN.
166 * more: Boolean. If non-zero the next filter entry is
167 * also to be applied to a packet.
169 * mask: A bit mask specifying the bits to compare.
171 * value: A value to compare against the masked bits at
172 * offset in a users packet.
174 * compNeq: Defines type of comarison (Equal or Notequal)
177 * fill: Round things out to a dword boundary
179 typedef struct ascend_generic_filter_t {
183 uint8_t mask[ RAD_MAX_FILTER_LEN ];
184 uint8_t value[ RAD_MAX_FILTER_LEN ];
186 uint8_t fill[3]; /* used to be fill[1] */
187 } ascend_generic_filter_t;
192 * A binary filter element. Contains one of ascend_ip_filter_t,
193 * ascend_ipx_filter_t, or ascend_generic_filter_t.
195 * All fields are stored in network byte order.
197 * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
199 * forward: TRUE if we should forward packets that match this
200 * filter, FALSE if we should drop packets that match
203 * direction: TRUE if this is an input filter, FALSE if this is
206 * fill: Round things out to a dword boundary.
209 * ip: An ip filter entry
210 * generic: A generic filter entry
212 typedef struct ascend_filter_t {
218 ascend_ip_filter_t ip;
219 ascend_ipx_filter_t ipx;
220 ascend_generic_filter_t generic;
221 uint8_t data[28]; /* ensure it's 32 bytes */
226 * This is a wild C hack...
228 typedef struct _cpp_hack {
229 char data[(sizeof(ascend_filter_t) == 32) ? 1 : -1 ];
235 * Ascii names of some well known tcp/udp services.
236 * Used for filtering on a port type.
238 * ??? What the heck is wrong with getservbyname?
240 static const LRAD_NAME_NUMBER filterPortType[] = {
245 { "nameserver", 42 },
262 static const LRAD_NAME_NUMBER filterType[] = {
263 { "generic", RAD_FILTER_GENERIC},
264 { "ip", RAD_FILTER_IP},
265 { "ipx", RAD_FILTER_IPX},
276 FILTER_GENERIC_OFFSET,
278 FILTER_GENERIC_VALUE,
279 FILTER_GENERIC_COMPNEQ,
280 FILTER_GENERIC_COMPEQ,
289 FILTER_IPX_DST_IPXNET,
290 FILTER_IPX_DST_IPXNODE,
291 FILTER_IPX_DST_IPXSOCK,
292 FILTER_IPX_SRC_IPXNET,
293 FILTER_IPX_SRC_IPXNODE,
294 FILTER_IPX_SRC_IPXSOCK
298 static const LRAD_NAME_NUMBER filterKeywords[] = {
299 { "ip", FILTER_IP_TYPE },
300 { "generic", FILTER_GENERIC_TYPE },
302 { "out", FILTER_OUT },
303 { "forward", FILTER_FORWARD },
304 { "drop", FILTER_DROP },
305 { "dstip", FILTER_IP_DST },
306 { "srcip", FILTER_IP_SRC },
307 { "dstport", FILTER_IP_DST_PORT },
308 { "srcport", FILTER_IP_SRC_PORT },
309 { "est", FILTER_EST },
310 { "more", FILTER_MORE },
311 { "!=", FILTER_GENERIC_COMPNEQ },
312 { "==", FILTER_GENERIC_COMPEQ },
313 { "ipx", FILTER_IPX_TYPE },
314 { "dstipxnet", FILTER_IPX_DST_IPXNET },
315 { "dstipxnode", FILTER_IPX_DST_IPXNODE },
316 { "dstipxsock", FILTER_IPX_DST_IPXSOCK },
317 { "srcipxnet", FILTER_IPX_SRC_IPXNET },
318 { "srcipxnode", FILTER_IPX_SRC_IPXNODE },
319 { "srcipxsock", FILTER_IPX_SRC_IPXSOCK },
326 * Ascii name of protocols used for filtering.
328 * ??? What the heck is wrong with getprotobyname?
330 static const LRAD_NAME_NUMBER filterProtoName[] = {
341 * RadFilterComparison:
343 * An enumerated values for the IP filter port comparisons.
350 RAD_COMPARE_NOT_EQUAL
351 } RadFilterComparison;
353 static const LRAD_NAME_NUMBER filterCompare[] = {
354 { "<", RAD_COMPARE_LESS },
355 { "=", RAD_COMPARE_EQUAL },
356 { ">", RAD_COMPARE_GREATER },
357 { "!=", RAD_COMPARE_NOT_EQUAL },
363 * String split routine. Splits an input string IN PLACE
364 * into pieces, based on spaces.
366 static int str2argv(char *str, char **argv, int max_argc)
371 if (argc >= max_argc) return argc;
373 while (*str == ' ') *(str++) = '\0';
375 if (!*str) return argc;
380 while (*str && (*str != ' ')) str++;
388 * ascend_parse_ipx_net
390 * srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]
392 static int ascend_parse_ipx_net(int argc, char **argv,
393 ascend_ipx_net_t *net, uint8_t *comp)
398 if (argc < 3) return -1;
401 * Parse the net, which is a hex number.
403 net->net = htonl(strtol(argv[0], NULL, 16));
408 token = lrad_str2int(filterKeywords, argv[1], -1);
410 case FILTER_IPX_SRC_IPXNODE:
411 case FILTER_IPX_DST_IPXNODE:
419 * Can have a leading "0x" or "0X"
422 if ((memcmp(p, "0X", 2) == 0) ||
423 (memcmp(p, "0x", 2) == 0)) p += 2;
426 * Node must be 6 octets long.
428 token = lrad_hex2bin(p, net->node, IPX_NODE_ADDR_LEN);
429 if (token != IPX_NODE_ADDR_LEN) return -1;
434 if (argc == 3) return 3;
437 * Can't be too little or too much.
439 if (argc != 6) return -1;
444 token = lrad_str2int(filterKeywords, argv[3], -1);
446 case FILTER_IPX_SRC_IPXSOCK:
447 case FILTER_IPX_DST_IPXSOCK:
455 * Parse the command "<", ">", "=" or "!="
457 token = lrad_str2int(filterCompare, argv[4], -1);
459 case RAD_COMPARE_LESS:
460 case RAD_COMPARE_EQUAL:
461 case RAD_COMPARE_GREATER:
462 case RAD_COMPARE_NOT_EQUAL:
473 token = strtoul(argv[5], NULL, 16);
474 if (token > 65535) return -1;
477 net->socket = htons(net->socket);
481 * Everything's OK, we parsed 6 entries.
487 * ascend_parse_ipx_filter
489 * This routine parses an IPX filter string from a string.
490 * The format of the string is:
492 * [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
493 * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
495 * Fields in [...] are optional.
498 * srcipxnet: Keyword for source IPX address.
499 * nnnn = IPX Node address.
501 * srcipxnode: Keyword for source IPX Node address.
502 * mmmmm = IPX Node Address, could be FFFFFF.
503 * A vlid ipx node number should accompany ipx net number.
505 * srcipxsoc: Keyword for source IPX socket address.
507 * cmd: One of ">" or "<" or "=" or "!=".
509 * value: Socket value to be compared against, in hex.
511 * dstipxnet: Keyword for destination IPX address.
512 * nnnn = IPX Node address.
514 * dstipxnode: Keyword for destination IPX Node address.
515 * mmmmm = IPX Node Address, could be FFFFFF.
516 * A valid ipx node number should accompany ipx net number.
518 * dstipxsoc: Keyword for destination IPX socket address.
520 * cmd: One of ">" or "<" or "=" or "!=".
522 * value: Socket value to be compared against, in hex.
524 static int ascend_parse_ipx(int argc, char **argv, ascend_ipx_filter_t *filter)
531 * We may have nothing, in which case we simply return.
533 if (argc == 0) return 0;
536 * Must have "net N node M"
538 if (argc < 4) return -1;
540 while ((argc > 0) && (flags != 0x03)) {
541 token = lrad_str2int(filterKeywords, argv[0], -1);
543 case FILTER_IPX_SRC_IPXNET:
544 if (flags & 0x01) return -1;
545 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
547 &(filter->srcSocComp));
548 if (rcode < 0) return -1;
554 case FILTER_IPX_DST_IPXNET:
555 if (flags & 0x02) return -1;
556 rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
558 &(filter->dstSocComp));
559 if (rcode < 0) return -1;
566 librad_log("Unknown string \"%s\" in IPX data filter",
573 * Arguments left over: die.
575 if (argc != 0) return -1;
585 * Parse an IP address and optionally a netmask, to a uint32_t.
587 * ipaddr should already be initialized to zero.
588 * ipaddr is in network byte order.
590 * Returns -1 on error, or the number of bits in the netmask, otherwise.
592 static int ascend_parse_ipaddr(uint32_t *ipaddr, char *str)
597 uint32_t netmask = 0;
603 while (*str && (count < 4) && (netmask == 0)) {
609 case '0': case '1': case '2': case '3':
610 case '4': case '5': case '6': case '7':
613 ip[count] += (*str) - '0';
618 case '.': /* dot between IP numbers. */
620 if (ip[count] > 255) return -1;
623 * 24, 16, 8, 0, done.
625 *ipaddr |= (ip[count] << (8 * (3 - count)));
629 case '/': /* netmask */
632 if ((masklen < 0) || (masklen > 32)) return -1;
633 str += strspn(str, "0123456789");
639 librad_log("Invalid character in IP address");
642 } /* loop over one character */
643 } /* loop until the count hits 4 */
648 * Do the last one, too.
650 if (ip[count] > 255) return -1;
653 * 24, 16, 8, 0, done.
655 *ipaddr |= (ip[count] << (8 * (3 - count)));
659 * We've hit the end of the IP address, and there's something
660 * else left over: die.
665 * Set the default netmask.
670 } else if ((*ipaddr & 0x80000000) == 0) {
672 } else if ((*ipaddr & 0xc0000000) == 0x80000000) {
674 } else if ((*ipaddr & 0xe0000000) == 0xc0000000) {
681 *ipaddr = htonl(*ipaddr);
686 * ascend_parse_port: Parse a comparator and port.
688 * Returns -1 on error, or the comparator.
690 static int ascend_parse_port(uint16_t *port, char *compare, char *str)
692 int rcode, token = -1;
695 * There MUST be a comparison string.
697 rcode = lrad_str2int(filterCompare, compare, -1);
698 if (rcode < 0) return rcode;
700 if (strspn(str, "0123456789") == strlen(str)) {
703 token = lrad_str2int(filterPortType, str, -1);
706 if ((token < 0) || (token > 65535)) return -1;
709 *port = htons(*port);
715 #define IP_SRC_ADDR_FLAG (1 << 0)
716 #define IP_DEST_ADDR_FLAG (1 << 1)
717 #define IP_SRC_PORT_FLAG (1 << 2)
718 #define IP_DEST_PORT_FLAG (1 << 3)
719 #define IP_PROTO_FLAG (1 << 4)
720 #define IP_EST_FLAG (1 << 5)
722 #define DONE_FLAGS (IP_SRC_ADDR_FLAG | IP_DEST_ADDR_FLAG | \
723 IP_SRC_PORT_FLAG | IP_DEST_PORT_FLAG | \
724 IP_PROTO_FLAG | IP_EST_FLAG)
729 * This routine parses an IP filter string from a RADIUS
730 * reply. The format of the string is:
732 * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
733 * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ]
735 * Fields in [...] are optional.
737 * dstip: Keyword for destination IP address.
738 * n.n.n.n = IP address. /nn - netmask.
740 * srcip: Keyword for source IP address.
741 * n.n.n.n = IP address. /nn - netmask.
743 * proto: Optional protocol field. Either a name or
744 * number. Known names are in FilterProtoName[].
746 * dstport: Keyword for destination port. Only valid with tcp
747 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
750 * srcport: Keyword for source port. Only valid with tcp
751 * or udp. 'cmp' are in FilterPortType[]. 'value' can be
754 * est: Keyword for TCP established. Valid only for tcp.
757 static int ascend_parse_ip(int argc, char **argv, ascend_ip_filter_t *filter)
764 * We may have nothing, in which case we simply return.
766 if (argc == 0) return 0;
769 * There may, or may not, be src & dst IP's in the string.
772 while ((argc > 0) && (flags != DONE_FLAGS)) {
773 token = lrad_str2int(filterKeywords, argv[0], -1);
776 if (flags & IP_SRC_ADDR_FLAG) return -1;
777 if (argc < 2) return -1;
779 rcode = ascend_parse_ipaddr(&filter->srcip, argv[1]);
780 if (rcode < 0) return rcode;
782 filter->srcmask = rcode;
783 flags |= IP_SRC_ADDR_FLAG;
789 if (flags & IP_DEST_ADDR_FLAG) return -1;
790 if (argc < 2) return -1;
792 rcode = ascend_parse_ipaddr(&filter->dstip, argv[1]);
793 if (rcode < 0) return rcode;
795 filter->dstmask = rcode;
796 flags |= IP_DEST_ADDR_FLAG;
801 case FILTER_IP_SRC_PORT:
802 if (flags & IP_SRC_PORT_FLAG) return -1;
803 if (argc < 3) return -1;
805 rcode = ascend_parse_port(&filter->srcport,
807 if (rcode < 0) return rcode;
808 filter->srcPortComp = rcode;
810 flags |= IP_SRC_PORT_FLAG;
815 case FILTER_IP_DST_PORT:
816 if (flags & IP_DEST_PORT_FLAG) return -1;
817 if (argc < 3) return -1;
819 rcode = ascend_parse_port(&filter->dstport,
821 if (rcode < 0) return rcode;
822 filter->dstPortComp = rcode;
824 flags |= IP_DEST_PORT_FLAG;
830 if (flags & IP_EST_FLAG) return -1;
831 filter->established = 1;
834 flags |= IP_EST_FLAG;
838 if (flags & IP_PROTO_FLAG) return -1;
839 if (strspn(argv[0], "0123456789") == strlen(argv[0])) {
840 token = atoi(argv[0]);
842 token = lrad_str2int(filterProtoName, argv[0], -1);
844 librad_log("Unknown IP protocol \"%s\" in IP data filter",
849 filter->proto = token;
850 flags |= IP_PROTO_FLAG;
859 * We should have parsed everything by now.
862 librad_log("Unknown extra string \"%s\" in IP data filter",
872 * ascend_parse_generic
874 * This routine parses a Generic filter string from a RADIUS
875 * reply. The format of the string is:
877 * generic dir action offset mask value [== or != ] [more]
879 * Fields in [...] are optional.
881 * offset: A Number. Specifies an offset into a frame
882 * to start comparing.
884 * mask: A hexadecimal mask of bits to compare.
886 * value: A value to compare with the masked data.
888 * compNeq: Defines type of comparison. ( "==" or "!=")
891 * more: Optional keyword MORE, to represent the attachment
894 static int ascend_parse_generic(int argc, char **argv,
895 ascend_generic_filter_t *filter)
902 * We may have nothing, in which case we simply return.
904 if (argc == 0) return 0;
907 * We need at least "offset mask value"
909 if (argc < 3) return -1;
912 * No more than optional comparison and "more"
914 if (argc > 5) return -1;
917 * Offset is a uint16_t number.
919 if (strspn(argv[0], "0123456789") != strlen(argv[0])) return -1;
921 rcode = atoi(argv[0]);
922 if (rcode > 65535) return -1;
924 filter->offset = rcode;
925 filter->offset = htons(filter->offset);
927 rcode = lrad_hex2bin(argv[1], filter->mask, sizeof(filter->mask));
928 if (rcode != sizeof(filter->mask)) return -1;
930 token = lrad_hex2bin(argv[2], filter->value, sizeof(filter->value));
931 if (token != sizeof(filter->value)) return -1;
934 * The mask and value MUST be the same length.
936 if (rcode != token) return -1;
939 filter->len = htons(filter->len);
942 * Nothing more. Exit.
944 if (argc == 3) return 0;
951 token = lrad_str2int(filterKeywords, argv[0], -1);
953 case FILTER_GENERIC_COMPNEQ:
954 if (flags & 0x01) return -1;
955 filter->compNeq = TRUE;
958 case FILTER_GENERIC_COMPEQ:
959 if (flags & 0x01) return -1;
960 filter->compNeq = FALSE;
965 if (flags & 0x02) return -1;
966 filter->more = htons( 1 );
971 librad_log("Invalid string \"%s\" in generic data filter",
987 * This routine will call routines to parse entries from an ASCII format
988 * to a binary format recognized by the Ascend boxes.
990 * pair: Pointer to value_pair to place return.
992 * valstr: The string to parse
994 * return: -1 for error or 0.
997 ascend_parse_filter(VALUE_PAIR *pair)
1003 ascend_filter_t filter;
1008 * Rather than printing specific error messages, we create
1009 * a general one here, which won't be used if the function
1012 librad_log("Text is not in proper format");
1015 * Tokenize the input string in the VP.
1017 * Once the filter is *completelty* parsed, then we will
1018 * over-write it with the final binary filter.
1020 argc = str2argv(pair->vp_strvalue, argv, 32);
1021 if (argc < 3) return -1;
1024 * Decide which filter type it is: ip, ipx, or generic
1026 type = lrad_str2int(filterType, argv[0], -1);
1027 memset(&filter, 0, sizeof(filter));
1030 * Validate the filter type.
1033 case RAD_FILTER_GENERIC:
1035 case RAD_FILTER_IPX:
1040 librad_log("Unknown Ascend filter type \"%s\"", argv[0]);
1048 token = lrad_str2int(filterKeywords, argv[1], -1);
1051 filter.direction = 1;
1055 filter.direction = 0;
1059 librad_log("Unknown Ascend filter direction \"%s\"", argv[1]);
1067 token = lrad_str2int(filterKeywords, argv[2], -1);
1069 case FILTER_FORWARD:
1078 librad_log("Unknown Ascend filter action \"%s\"", argv[2]);
1085 case RAD_FILTER_GENERIC:
1086 rcode = ascend_parse_generic(argc - 3, &argv[3],
1091 rcode = ascend_parse_ip(argc - 3, &argv[3], &filter.u.ip);
1094 case RAD_FILTER_IPX:
1095 rcode = ascend_parse_ipx(argc - 3, &argv[3], &filter.u.ipx);
1098 default: /* should never reach here. */
1103 * Touch the VP only if everything was OK.
1106 pair->length = sizeof(filter);
1107 memcpy(pair->vp_filter, &filter, sizeof(filter));
1114 * if 'more' is set then this new entry must exist, be a
1115 * FILTER_GENERIC_TYPE, direction and disposition must match for
1116 * the previous 'more' to be valid. If any should fail then TURN OFF
1120 filt = ( RadFilter * )prevRadPair->vp_strvalue;
1121 if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
1122 ( prevRadPair->attribute != pair->attribute ) ||
1123 ( filt->indirection != radFil.indirection ) ||
1124 ( filt->forward != radFil.forward ) ) {
1125 gen = &filt->u.generic;
1127 librad_log("filterBinary: 'more' for previous entry doesn't match: %s.\n",
1132 if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
1133 if( radFil.u.generic.more ) {
1139 memcpy( pair->vp_strvalue, &radFil, pair->length );
1147 * Print an Ascend binary filter attribute to a string,
1148 * Grrr... Ascend makes the server do this work, instead
1149 * of doing it on the NAS.
1151 * Note we don't bother checking 'len' after the snprintf's.
1152 * This function should ONLY be called with a large (~1k) buffer.
1154 void print_abinary(VALUE_PAIR *vp, char *buffer, int len)
1158 ascend_filter_t *filter;
1160 static const char *action[] = {"drop", "forward"};
1161 static const char *direction[] = {"out", "in"};
1166 * Just for paranoia: wrong size filters get printed as octets
1168 if (vp->length != sizeof(*filter)) {
1172 for (i = 0; i < vp->length; i++) {
1173 snprintf(p, len, "%02x", vp->vp_octets[i]);
1181 len -= 3; /* account for leading & trailing quotes */
1183 filter = (ascend_filter_t *) &(vp->vp_filter);
1184 i = snprintf(p, len, "%s %s %s",
1185 lrad_int2str(filterType, filter->type, "??"),
1186 direction[filter->direction & 0x01],
1187 action[filter->forward & 0x01]);
1195 if (filter->type == RAD_FILTER_IP) {
1197 if (filter->u.ip.srcip) {
1198 i = snprintf(p, len, " srcip %d.%d.%d.%d/%d",
1199 ((uint8_t *) &filter->u.ip.srcip)[0],
1200 ((uint8_t *) &filter->u.ip.srcip)[1],
1201 ((uint8_t *) &filter->u.ip.srcip)[2],
1202 ((uint8_t *) &filter->u.ip.srcip)[3],
1203 filter->u.ip.srcmask);
1208 if (filter->u.ip.dstip) {
1209 i = snprintf(p, len, " dstip %d.%d.%d.%d/%d",
1210 ((uint8_t *) &filter->u.ip.dstip)[0],
1211 ((uint8_t *) &filter->u.ip.dstip)[1],
1212 ((uint8_t *) &filter->u.ip.dstip)[2],
1213 ((uint8_t *) &filter->u.ip.dstip)[3],
1214 filter->u.ip.dstmask);
1219 i = snprintf(p, len, " %s",
1220 lrad_int2str(filterProtoName, filter->u.ip.proto, "??"));
1224 if (filter->u.ip.srcPortComp > RAD_NO_COMPARE) {
1225 i = snprintf(p, len, " srcport %s %d",
1226 lrad_int2str(filterCompare, filter->u.ip.srcPortComp, "??"),
1227 ntohs(filter->u.ip.srcport));
1232 if (filter->u.ip.dstPortComp > RAD_NO_COMPARE) {
1233 i = snprintf(p, len, " dstport %s %d",
1234 lrad_int2str(filterCompare, filter->u.ip.dstPortComp, "??"),
1235 ntohs(filter->u.ip.dstport));
1240 if (filter->u.ip.established) {
1241 i = snprintf(p, len, " est");
1247 * Handle IPX filters
1249 } else if (filter->type == RAD_FILTER_IPX) {
1250 /* print for source */
1251 if (filter->u.ipx.src.net) {
1252 i = snprintf(p, len, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
1253 (unsigned int)ntohl(filter->u.ipx.src.net),
1254 filter->u.ipx.src.node[0], filter->u.ipx.src.node[1],
1255 filter->u.ipx.src.node[2], filter->u.ipx.src.node[3],
1256 filter->u.ipx.src.node[4], filter->u.ipx.src.node[5]);
1260 if (filter->u.ipx.srcSocComp > RAD_NO_COMPARE) {
1261 i = snprintf(p, len, " srcipxsock %s 0x%04x",
1262 lrad_int2str(filterCompare, filter->u.ipx.srcSocComp, "??"),
1263 ntohs(filter->u.ipx.src.socket));
1269 /* same for destination */
1270 if (filter->u.ipx.dst.net) {
1271 i = snprintf(p, len, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
1272 (unsigned int)ntohl(filter->u.ipx.dst.net),
1273 filter->u.ipx.dst.node[0], filter->u.ipx.dst.node[1],
1274 filter->u.ipx.dst.node[2], filter->u.ipx.dst.node[3],
1275 filter->u.ipx.dst.node[4], filter->u.ipx.dst.node[5]);
1279 if (filter->u.ipx.dstSocComp > RAD_NO_COMPARE) {
1280 i = snprintf(p, len, " dstipxsock %s 0x%04x",
1281 lrad_int2str(filterCompare, filter->u.ipx.dstSocComp, "??"),
1282 ntohs(filter->u.ipx.dst.socket));
1289 } else if (filter->type == RAD_FILTER_GENERIC) {
1292 i = snprintf(p, len, " %u ", (unsigned int) ntohs(filter->u.generic.offset));
1297 for (count = 0; count < ntohs(filter->u.generic.len); count++) {
1298 i = snprintf(p, len, "%02x", filter->u.generic.mask[count]);
1307 /* show the value */
1308 for (count = 0; count < ntohs(filter->u.generic.len); count++) {
1309 i = snprintf(p, len, "%02x", filter->u.generic.value[count]);
1314 i = snprintf(p, len, " %s", (filter->u.generic.compNeq) ? "!=" : "==");
1318 if (filter->u.generic.more != 0) {
1319 i = snprintf(p, len, " more");