📄 filters.c
字号:
/* * filters.c Routines to parse Ascend's filter attributes. * * Version: $Id: filters.c,v 1.36 2004/02/26 19:04:20 aland Exp $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * * Copyright 2003 The FreeRADIUS server project */static const char rcsid[] = "$Id: filters.c,v 1.36 2004/02/26 19:04:20 aland Exp $";#include <string.h>#include <ctype.h>#include <stdlib.h>#include "libradius.h"#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif/* * Two types of filters are supported, GENERIC and IP. The identifiers * are: */#define RAD_FILTER_GENERIC 0#define RAD_FILTER_IP 1#define RAD_FILTER_IPX 2/* * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes * starting at some offset. The length is: */#define RAD_MAX_FILTER_LEN 6/* * ASCEND extensions for ABINARY filters */#define IPX_NODE_ADDR_LEN 6#if ! defined( FALSE )# define FALSE 0# define TRUE (! FALSE)#endif/* * ascend_ip_filter_t * * The binary format of an IP filter. ALL fields are stored in * network byte order. * * srcip: The source IP address. * * dstip: The destination IP address. * * srcmask: The number of leading one bits in the source address * mask. Specifies the bits of interest. * * dstmask: The number of leading one bits in the destination * address mask. Specifies the bits of interest. * * proto: The IP protocol number * * established: A boolean value. TRUE when we care about the * established state of a TCP connection. FALSE when * we dont care. * * srcport: TCP or UDP source port number. * * dstport: TCP or UDP destination port number. * * srcPortCmp: One of the values of the RadFilterComparison * enumeration, specifying how to compare the * srcport value. * * dstPortCmp: One of the values of the RadFilterComparison * enumeration, specifying how to compare the * dstport value. * * fill: Round things out to a int16_t boundary. */typedef struct ascend_ip_filter_t { uint32_t srcip; uint32_t dstip; uint8_t srcmask; uint8_t dstmask; uint8_t proto; uint8_t established; uint16_t srcport; uint16_t dstport; uint8_t srcPortComp; uint8_t dstPortComp; unsigned char fill[4]; /* used to be fill[2] */} ascend_ip_filter_t;/* * ascend_ipx_net_t * * net: IPX Net address * * node: IPX Node address * * socket: IPX socket address */typedef struct ascend_ipx_net_t { uint32_t net; uint8_t node[IPX_NODE_ADDR_LEN]; uint16_t socket;} ascend_ipx_net_t;/* * ascend_ipx_filter_t * * The binary format of an IPX filter. ALL fields are stored in * network byte order. * * src: Source net, node, and socket. * * dst: Destination net, node, and socket. * * srcSocComp: Source socket compare value * * dstSocComp: Destination socket compare value */typedef struct ascend_ipx_filter_t { ascend_ipx_net_t src; ascend_ipx_net_t dst; uint8_t srcSocComp; uint8_t dstSocComp;} ascend_ipx_filter_t;/* * ascend_generic_filter_t * * The binary format of a GENERIC filter. ALL fields are stored in * network byte order. * * offset: Number of bytes into packet to start comparison. * * len: Number of bytes to mask and compare. May not * exceed RAD_MAX_FILTER_LEN. * * more: Boolean. If non-zero the next filter entry is * also to be applied to a packet. * * mask: A bit mask specifying the bits to compare. * * value: A value to compare against the masked bits at * offset in a users packet. * * compNeq: Defines type of comarison (Equal or Notequal) * default is Equal. * * fill: Round things out to a dword boundary */typedef struct ascend_generic_filter_t { uint16_t offset; uint16_t len; uint16_t more; uint8_t mask[ RAD_MAX_FILTER_LEN ]; uint8_t value[ RAD_MAX_FILTER_LEN ]; uint8_t compNeq; uint8_t fill[3]; /* used to be fill[1] */} ascend_generic_filter_t;/* * ascend_filter_t * * A binary filter element. Contains one of ascend_ip_filter_t, * ascend_ipx_filter_t, or ascend_generic_filter_t. * * All fields are stored in network byte order. * * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP. * * forward: TRUE if we should forward packets that match this * filter, FALSE if we should drop packets that match * this filter. * * direction: TRUE if this is an input filter, FALSE if this is * an output filter. * * fill: Round things out to a dword boundary. * * u: A union of * ip: An ip filter entry * generic: A generic filter entry */typedef struct ascend_filter_t { uint8_t type; uint8_t forward; uint8_t direction; uint8_t fill; union { ascend_ip_filter_t ip; ascend_ipx_filter_t ipx; ascend_generic_filter_t generic; } u;} ascend_filter_t;#define SIZEOF_RADFILTER 32/* * FilterPortType: * * Ascii names of some well known tcp/udp services. * Used for filtering on a port type. * * ??? What the heck is wrong with getservbyname? */static const LRAD_NAME_NUMBER filterPortType[] = { { "ftp-data", 20 }, { "ftp", 21 }, { "telnet", 23 }, { "smtp", 25 }, { "nameserver", 42 }, { "domain", 53 }, { "tftp", 69 }, { "gopher", 70 }, { "finger", 79 }, { "www", 80 }, { "kerberos", 88 }, { "hostname", 101 }, { "nntp", 119 }, { "ntp", 123 }, { "exec", 512 }, { "login", 513 }, { "cmd", 514 }, { "talk", 517 }, { NULL , 0},};static const LRAD_NAME_NUMBER filterType[] = { { "generic", RAD_FILTER_GENERIC}, { "ip", RAD_FILTER_IP}, { "ipx", RAD_FILTER_IPX}, { NULL, 0},};typedef enum { FILTER_GENERIC_TYPE, FILTER_IP_TYPE, FILTER_IN, FILTER_OUT, FILTER_FORWARD, FILTER_DROP, FILTER_GENERIC_OFFSET, FILTER_GENERIC_MASK, FILTER_GENERIC_VALUE, FILTER_GENERIC_COMPNEQ, FILTER_GENERIC_COMPEQ, FILTER_MORE, FILTER_IP_DST, FILTER_IP_SRC, FILTER_IP_PROTO, FILTER_IP_DST_PORT, FILTER_IP_SRC_PORT, FILTER_EST, FILTER_IPX_TYPE, FILTER_IPX_DST_IPXNET, FILTER_IPX_DST_IPXNODE, FILTER_IPX_DST_IPXSOCK, FILTER_IPX_SRC_IPXNET, FILTER_IPX_SRC_IPXNODE, FILTER_IPX_SRC_IPXSOCK} FilterTokens;static const LRAD_NAME_NUMBER filterKeywords[] = { { "ip", FILTER_IP_TYPE }, { "generic", FILTER_GENERIC_TYPE }, { "in", FILTER_IN }, { "out", FILTER_OUT }, { "forward", FILTER_FORWARD }, { "drop", FILTER_DROP }, { "dstip", FILTER_IP_DST }, { "srcip", FILTER_IP_SRC }, { "dstport", FILTER_IP_DST_PORT }, { "srcport", FILTER_IP_SRC_PORT }, { "est", FILTER_EST }, { "more", FILTER_MORE }, { "!=", FILTER_GENERIC_COMPNEQ }, { "==", FILTER_GENERIC_COMPEQ }, { "ipx", FILTER_IPX_TYPE }, { "dstipxnet", FILTER_IPX_DST_IPXNET }, { "dstipxnode", FILTER_IPX_DST_IPXNODE }, { "dstipxsock", FILTER_IPX_DST_IPXSOCK }, { "srcipxnet", FILTER_IPX_SRC_IPXNET }, { "srcipxnode", FILTER_IPX_SRC_IPXNODE }, { "srcipxsock", FILTER_IPX_SRC_IPXSOCK }, { NULL , -1},};/* * FilterProtoName: * * Ascii name of protocols used for filtering. * * ??? What the heck is wrong with getprotobyname? */static const LRAD_NAME_NUMBER filterProtoName[] = { { "tcp", 6 }, { "udp", 17 }, { "ospf", 89 }, { "icmp", 1 }, { "0", 0 }, { NULL , -1 },};/* * RadFilterComparison: * * An enumerated values for the IP filter port comparisons. */typedef enum { RAD_NO_COMPARE = 0, RAD_COMPARE_LESS, RAD_COMPARE_EQUAL, RAD_COMPARE_GREATER, RAD_COMPARE_NOT_EQUAL} RadFilterComparison;static const LRAD_NAME_NUMBER filterCompare[] = { { "<", RAD_COMPARE_LESS }, { "=", RAD_COMPARE_EQUAL }, { ">", RAD_COMPARE_GREATER }, { "!=", RAD_COMPARE_NOT_EQUAL }, { NULL, 0 },};/* * String split routine. Splits an input string IN PLACE * into pieces, based on spaces. */static int str2argv(char *str, char **argv, int max_argc){ int argc = 0; while (*str) { if (argc >= max_argc) return argc; while (*str == ' ') *(str++) = '\0'; if (!*str) return argc; argv[argc] = str; argc++; while (*str && (*str != ' ')) str++; } return argc;}/* * hex2bin converts hexadecimal strings into binary * * Hmm... there are a number of such functions in the source. * maybe we want to make a library function? */static int hex2bin(const char *str, uint8_t *bin, size_t length){ unsigned int len; const char *letters = "0123456789ABCDEFabcdef"; /* * Must be byte aligned, not nibble aligned. */ len = strlen(str); if ((len & 0x01) != 0) return -1; /* * Input string is too long to fit. Don't even bother * trying. */ if ((len / 2) > length) return -1; /* * Input string contains non-hex characters, die. */ if (strspn(str, letters) != len) return -1; len = 0; while (*str) { char *c1, *c2; c1 = memchr(letters, toupper((int) *(str++)), 16); c2 = memchr(letters, toupper((int) *(str++)), 16); *(bin++) = ((c1-letters)<<4) + (c2-letters); len++; } return len;}/* * ascend_parse_ipx_net * * srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ] */static int ascend_parse_ipx_net(int argc, char **argv, ascend_ipx_net_t *net, uint8_t *comp){ int token; const char *p; if (argc < 3) return -1; /* * Parse the net, which is a hex number. */ net->net = htonl(strtol(argv[0], NULL, 16)); /* * Parse the node. */ token = lrad_str2int(filterKeywords, argv[1], -1); switch (token) { case FILTER_IPX_SRC_IPXNODE: case FILTER_IPX_DST_IPXNODE: break; default: return -1; } /* * Can have a leading "0x" or "0X" */ p = argv[2]; if ((memcmp(p, "0X", 2) == 0) || (memcmp(p, "0x", 2) == 0)) p += 2; /* * Node must be 6 octets long. */ token = hex2bin(p, net->node, IPX_NODE_ADDR_LEN); if (token != IPX_NODE_ADDR_LEN) return -1; /* * Nothing more, die. */ if (argc == 3) return 3; /* * Can't be too little or too much. */ if (argc != 6) return -1; /* * Parse the socket. */ token = lrad_str2int(filterKeywords, argv[3], -1); switch (token) { case FILTER_IPX_SRC_IPXSOCK: case FILTER_IPX_DST_IPXSOCK: break; default: return -1; } /* * Parse the command "<", ">", "=" or "!=" */ token = lrad_str2int(filterCompare, argv[4], -1); switch (token) { case RAD_COMPARE_LESS: case RAD_COMPARE_EQUAL: case RAD_COMPARE_GREATER: case RAD_COMPARE_NOT_EQUAL: *comp = token; break; default: return -1; } /* * Parse the value. */ token = strtoul(argv[5], NULL, 16); if (token > 65535) return -1; net->socket = token; net->socket = htons(net->socket); /* * Everything's OK, we parsed 6 entries. */ return 6;}/* * ascend_parse_ipx_filter * * This routine parses an IPX filter string from a string. * The format of the string is: * * [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]] * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]] * * Fields in [...] are optional. * where: * * srcipxnet: Keyword for source IPX address. * nnnn = IPX Node address. * * srcipxnode: Keyword for source IPX Node address. * mmmmm = IPX Node Address, could be FFFFFF. * A vlid ipx node number should accompany ipx net number. * * srcipxsoc: Keyword for source IPX socket address. * * cmd: One of ">" or "<" or "=" or "!=". * * value: Socket value to be compared against, in hex. * * dstipxnet: Keyword for destination IPX address. * nnnn = IPX Node address. * * dstipxnode: Keyword for destination IPX Node address. * mmmmm = IPX Node Address, could be FFFFFF. * A valid ipx node number should accompany ipx net number. * * dstipxsoc: Keyword for destination IPX socket address. * * cmd: One of ">" or "<" or "=" or "!=". * * value: Socket value to be compared against, in hex. */static int ascend_parse_ipx(int argc, char **argv, ascend_ipx_filter_t *filter){ int rcode; int token; int flags = 0; /* * We may have nothing, in which case we simply return. */ if (argc == 0) return 0; /* * Must have "net N node M" */ if (argc < 4) return -1; while ((argc > 0) && (flags != 0x03)) { token = lrad_str2int(filterKeywords, argv[0], -1); switch (token) { case FILTER_IPX_SRC_IPXNET: if (flags & 0x01) return -1; rcode = ascend_parse_ipx_net(argc - 1, argv + 1, &(filter->src), &(filter->srcSocComp)); if (rcode < 0) return -1; argc -= (rcode + 1); argv += rcode + 1; flags |= 0x01; break; case FILTER_IPX_DST_IPXNET: if (flags & 0x02) return -1; rcode = ascend_parse_ipx_net(argc - 1, argv + 1, &(filter->dst), &(filter->dstSocComp)); if (rcode < 0) return -1; argc -= (rcode + 1); argv += rcode + 1; flags |= 0x02; break; default: librad_log("Unknown string \"%s\" in IPX data filter", argv[0]); return -1; } } /* * Arguments left over: die. */ if (argc != 0) return -1; /* * Everything's OK. */ return 0;}/* * Parse an IP address and optionally a netmask, to a uint32_t. * * ipaddr should already be initialized to zero. * ipaddr is in network byte order. * * Returns -1 on error, or the number of bits in the netmask, otherwise. */static int ascend_parse_ipaddr(uint32_t *ipaddr, char *str){ int count = 0; int ip[4]; int masklen; uint32_t netmask = 0; /* * Look for IP's. */ count = 0; while (*str && (count < 4) && (netmask == 0)) { next: ip[count] = 0; while (*str) { switch (*str) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ip[count] *= 10; ip[count] += (*str) - '0'; str++; break; case '.': /* dot between IP numbers. */ str++; if (ip[count] > 255) return -1; /* * 24, 16, 8, 0, done. */ *ipaddr |= (ip[count] << (8 * (3 - count))); count++; goto next; case '/': /* netmask */ str++; masklen = atoi(str); if ((masklen < 0) || (masklen > 32)) return -1; str += strspn(str, "0123456789"); netmask = masklen; goto finalize; break; default: librad_log("Invalid character in IP address"); return -1; } } /* loop over one character */ } /* loop until the count hits 4 */ if (count == 3) { finalize: /* * Do the last one, too. */ if (ip[count] > 255) return -1; /* * 24, 16, 8, 0, done.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -