summaryrefslogtreecommitdiffstats
path: root/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'common.c')
-rw-r--r--common.c610
1 files changed, 610 insertions, 0 deletions
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..fa21fc9
--- /dev/null
+++ b/common.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 1993-2001 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(__sgi) && (IRIX > 602)
+# include <sys/ptimers.h>
+#endif
+#include <sys/types.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#if __FreeBSD_version >= 300000
+# include <net/if_var.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <ctype.h>
+#include <syslog.h>
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ipf.h"
+#include "facpri.h"
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 darrenr Exp $";
+#endif
+
+extern struct ipopt_names ionames[], secclass[];
+extern int opts;
+extern int use_inet6;
+
+
+char *proto = NULL;
+char flagset[] = "FSRPAUEC";
+u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG,
+ TH_ECN, TH_CWR };
+
+void fill6bits __P((int, u_32_t *));
+int count6bits __P((u_32_t *));
+
+static char thishost[MAXHOSTNAMELEN];
+
+
+void initparse()
+{
+ gethostname(thishost, sizeof(thishost));
+ thishost[sizeof(thishost) - 1] = '\0';
+}
+
+
+int genmask(msk, mskp)
+char *msk;
+u_32_t *mskp;
+{
+ char *endptr = NULL;
+#ifdef USE_INET6
+ u_32_t addr;
+#endif
+ int bits;
+
+ if (index(msk, '.') || index(msk, 'x') || index(msk, ':')) {
+ /* possibly of the form xxx.xxx.xxx.xxx
+ * or 0xYYYYYYYY */
+#ifdef USE_INET6
+ if (use_inet6) {
+ if (inet_pton(AF_INET6, msk, &addr) != 1)
+ return -1;
+ } else
+#endif
+ if (inet_aton(msk, (struct in_addr *)mskp) == 0)
+ return -1;
+ } else {
+ /*
+ * set x most significant bits
+ */
+ bits = (int)strtol(msk, &endptr, 0);
+ if ((*endptr != '\0') ||
+ ((bits > 32) && !use_inet6) || (bits < 0) ||
+ ((bits > 128) && use_inet6))
+ return -1;
+ if (use_inet6)
+ fill6bits(bits, mskp);
+ else {
+ if (bits == 0)
+ *mskp = 0;
+ else
+ *mskp = htonl(0xffffffff << (32 - bits));
+ }
+ }
+ return 0;
+}
+
+
+
+void fill6bits(bits, msk)
+int bits;
+u_32_t *msk;
+{
+ int i;
+
+ for (i = 0; bits >= 32 && i < 4 ; ++i, bits -= 32)
+ msk[i] = 0xffffffff;
+
+ if (bits > 0 && i < 4)
+ msk[i++] = htonl(0xffffffff << (32 - bits));
+
+ while (i < 4)
+ msk[i++] = 0;
+}
+
+
+/*
+ * returns -1 if neither "hostmask/num" or "hostmask mask addr" are
+ * found in the line segments, there is an error processing this information,
+ * or there is an error processing ports information.
+ */
+int hostmask(seg, sa, msk, pp, cp, tp, linenum)
+char ***seg;
+u_32_t *sa, *msk;
+u_short *pp, *tp;
+int *cp;
+int linenum;
+{
+ struct in_addr maskaddr;
+ char *s;
+
+ /*
+ * is it possibly hostname/num ?
+ */
+ if ((s = index(**seg, '/')) ||
+ ((s = index(**seg, ':')) && !index(s + 1, ':'))) {
+ *s++ = '\0';
+ if (genmask(s, msk) == -1) {
+ fprintf(stderr, "%d: bad mask (%s)\n", linenum, s);
+ return -1;
+ }
+ if (hostnum(sa, **seg, linenum) == -1) {
+ fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
+ return -1;
+ }
+ *sa &= *msk;
+ (*seg)++;
+ return ports(seg, pp, cp, tp, linenum);
+ }
+
+ /*
+ * look for extra segments if "mask" found in right spot
+ */
+ if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) {
+ if (hostnum(sa, **seg, linenum) == -1) {
+ fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
+ return -1;
+ }
+ (*seg)++;
+ (*seg)++;
+ if (inet_aton(**seg, &maskaddr) == 0) {
+ fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg);
+ return -1;
+ }
+ *msk = maskaddr.s_addr;
+ (*seg)++;
+ *sa &= *msk;
+ return ports(seg, pp, cp, tp, linenum);
+ }
+
+ if (**seg) {
+ if (hostnum(sa, **seg, linenum) == -1) {
+ fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
+ return -1;
+ }
+ (*seg)++;
+ if (use_inet6) {
+ u_32_t k = 0;
+ if (sa[0] || sa[1] || sa[2] || sa[3])
+ k = 0xffffffff;
+ msk[0] = msk[1] = msk[2] = msk[3] = k;
+ }
+ else
+ *msk = *sa ? 0xffffffff : 0;
+ return ports(seg, pp, cp, tp, linenum);
+ }
+ fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
+ return -1;
+}
+
+/*
+ * returns an ip address as a long var as a result of either a DNS lookup or
+ * straight inet_addr() call
+ */
+int hostnum(ipa, host, linenum)
+u_32_t *ipa;
+char *host;
+int linenum;
+{
+ struct hostent *hp;
+ struct netent *np;
+ struct in_addr ip;
+
+ if (!strcasecmp("any", host))
+ return 0;
+#ifdef USE_INET6
+ if (use_inet6) {
+ if (inet_pton(AF_INET6, host, ipa) == 1)
+ return 0;
+ else
+ return -1;
+ }
+#endif
+ if (isdigit(*host) && inet_aton(host, &ip)) {
+ *ipa = ip.s_addr;
+ return 0;
+ }
+
+ if (!strcasecmp("<thishost>", host))
+ host = thishost;
+
+ if (!(hp = gethostbyname(host))) {
+ if (!(np = getnetbyname(host))) {
+ fprintf(stderr, "%d: can't resolve hostname: %s\n",
+ linenum, host);
+ return -1;
+ }
+ *ipa = htonl(np->n_net);
+ return 0;
+ }
+ *ipa = *(u_32_t *)hp->h_addr;
+ return 0;
+}
+
+
+/*
+ * check for possible presence of the port fields in the line
+ */
+int ports(seg, pp, cp, tp, linenum)
+char ***seg;
+u_short *pp, *tp;
+int *cp;
+int linenum;
+{
+ int comp = -1;
+
+ if (!*seg || !**seg || !***seg)
+ return 0;
+ if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) {
+ (*seg)++;
+ if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq"))
+ comp = FR_EQUAL;
+ else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne"))
+ comp = FR_NEQUAL;
+ else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt"))
+ comp = FR_LESST;
+ else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt"))
+ comp = FR_GREATERT;
+ else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le"))
+ comp = FR_LESSTE;
+ else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge"))
+ comp = FR_GREATERTE;
+ else if (isalnum(***seg) && *(*seg + 2)) {
+ if (portnum(**seg, pp, linenum) == 0)
+ return -1;
+ (*seg)++;
+ if (!strcmp(**seg, "<>"))
+ comp = FR_OUTRANGE;
+ else if (!strcmp(**seg, "><"))
+ comp = FR_INRANGE;
+ else {
+ fprintf(stderr,
+ "%d: unknown range operator (%s)\n",
+ linenum, **seg);
+ return -1;
+ }
+ (*seg)++;
+ if (**seg == NULL) {
+ fprintf(stderr, "%d: missing 2nd port value\n",
+ linenum);
+ return -1;
+ }
+ if (portnum(**seg, tp, linenum) == 0)
+ return -1;
+ } else {
+ fprintf(stderr, "%d: unknown comparator (%s)\n",
+ linenum, **seg);
+ return -1;
+ }
+ if (comp != FR_OUTRANGE && comp != FR_INRANGE) {
+ (*seg)++;
+ if (portnum(**seg, pp, linenum) == 0)
+ return -1;
+ }
+ *cp = comp;
+ (*seg)++;
+ }
+ return 0;
+}
+
+
+/*
+ * find the port number given by the name, either from getservbyname() or
+ * straight atoi(). Return 1 on success, 0 on failure
+ */
+int portnum(name, port, linenum)
+char *name;
+u_short *port;
+int linenum;
+{
+ struct servent *sp, *sp2;
+ u_short p1 = 0;
+ int i;
+
+ if (isdigit(*name)) {
+ if (ratoi(name, &i, 0, USHRT_MAX)) {
+ *port = (u_short)i;
+ return 1;
+ }
+ fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name);
+ return 0;
+ }
+ if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) {
+ sp = getservbyname(name, proto);
+ if (sp) {
+ *port = ntohs(sp->s_port);
+ return 1;
+ }
+ fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name);
+ return 0;
+ }
+ sp = getservbyname(name, "tcp");
+ if (sp)
+ p1 = sp->s_port;
+ sp2 = getservbyname(name, "udp");
+ if (!sp || !sp2) {
+ fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n",
+ linenum, name);
+ return 0;
+ }
+ if (p1 != sp2->s_port) {
+ fprintf(stderr, "%d: %s %d/tcp is a different port to ",
+ linenum, name, p1);
+ fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port);
+ return 0;
+ }
+ *port = ntohs(p1);
+ return 1;
+}
+
+
+u_char tcp_flags(flgs, mask, linenum)
+char *flgs;
+u_char *mask;
+int linenum;
+{
+ u_char tcpf = 0, tcpfm = 0, *fp = &tcpf;
+ char *s, *t;
+
+ if (*flgs == '0') {
+ s = strchr(flgs, '/');
+ if (s)
+ *s++ = '\0';
+ tcpf = strtol(flgs, NULL, 0);
+ fp = &tcpfm;
+ } else
+ s = flgs;
+
+ for (; *s; s++) {
+ if (*s == '/' && fp == &tcpf) {
+ fp = &tcpfm;
+ if (*(s + 1) == '0')
+ break;
+ continue;
+ }
+ if (!(t = index(flagset, *s))) {
+ fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s);
+ return 0;
+ }
+ *fp |= flags[t - flagset];
+ }
+
+ if (s && *s == '0')
+ tcpfm = strtol(s, NULL, 0);
+
+ if (!tcpfm) {
+ if (tcpf == TH_SYN)
+ tcpfm = 0xff & ~(TH_ECN|TH_CWR);
+ else
+ tcpfm = 0xff & ~(TH_ECN);
+ }
+ *mask = tcpfm;
+ return tcpf;
+}
+
+
+/*
+ * count consecutive 1's in bit mask. If the mask generated by counting
+ * consecutive 1's is different to that passed, return -1, else return #
+ * of bits.
+ */
+int countbits(ip)
+u_32_t ip;
+{
+ u_32_t ipn;
+ int cnt = 0, i, j;
+
+ ip = ipn = ntohl(ip);
+ for (i = 32; i; i--, ipn *= 2)
+ if (ipn & 0x80000000)
+ cnt++;
+ else
+ break;
+ ipn = 0;
+ for (i = 32, j = cnt; i; i--, j--) {
+ ipn *= 2;
+ if (j > 0)
+ ipn++;
+ }
+ if (ipn == ip)
+ return cnt;
+ return -1;
+}
+
+
+int count6bits(msk)
+u_32_t *msk;
+{
+ int i = 0, k;
+ u_32_t j;
+
+ for (k = 3; k >= 0; k--)
+ if (msk[k] == 0xffffffff)
+ i += 32;
+ else {
+ for (j = msk[k]; j; j <<= 1)
+ if (j & 0x80000000)
+ i++;
+ }
+ return i;
+}
+
+
+char *portname(pr, port)
+int pr, port;
+{
+ static char buf[32];
+ struct protoent *p = NULL;
+ struct servent *sv = NULL, *sv1 = NULL;
+
+ if (pr == -1) {
+ if ((sv = getservbyport(htons(port), "tcp"))) {
+ strncpy(buf, sv->s_name, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ sv1 = getservbyport(htons(port), "udp");
+ sv = strncasecmp(buf, sv->s_name, strlen(buf)) ?
+ NULL : sv1;
+ }
+ if (sv)
+ return buf;
+ } else if (pr && (p = getprotobynumber(pr))) {
+ if ((sv = getservbyport(htons(port), p->p_name))) {
+ strncpy(buf, sv->s_name, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ return buf;
+ }
+ }
+
+ (void) sprintf(buf, "%d", port);
+ return buf;
+}
+
+
+int ratoi(ps, pi, min, max)
+char *ps;
+int *pi, min, max;
+{
+ int i;
+ char *pe;
+
+ i = (int)strtol(ps, &pe, 0);
+ if (*pe != '\0' || i < min || i > max)
+ return 0;
+ *pi = i;
+ return 1;
+}
+
+
+int ratoui(ps, pi, min, max)
+char *ps;
+u_int *pi, min, max;
+{
+ u_int i;
+ char *pe;
+
+ i = (u_int)strtol(ps, &pe, 0);
+ if (*pe != '\0' || i < min || i > max)
+ return 0;
+ *pi = i;
+ return 1;
+}
+
+
+void printhostmask(v, addr, mask)
+int v;
+u_32_t *addr, *mask;
+{
+ struct in_addr ipa;
+ int ones;
+
+#ifdef USE_INET6
+ if (v == 6) {
+ ones = count6bits(mask);
+ if (ones == 0 && !addr[0] && !addr[1] && !addr[2] && !addr[3])
+ printf("any");
+ else {
+ char ipbuf[64];
+ printf("%s/%d",
+ inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf)),
+ ones);
+ }
+ }
+ else
+#endif
+ if (!*addr && !*mask)
+ printf("any");
+ else {
+ ipa.s_addr = *addr;
+ printf("%s", inet_ntoa(ipa));
+ if ((ones = countbits(*mask)) == -1) {
+ ipa.s_addr = *mask;
+ printf("/%s", inet_ntoa(ipa));
+ } else
+ printf("/%d", ones);
+ }
+}
+
+
+void printportcmp(pr, frp)
+int pr;
+frpcmp_t *frp;
+{
+ static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=",
+ "<>", "><"};
+
+ if (frp->frp_cmp == FR_INRANGE || frp->frp_cmp == FR_OUTRANGE)
+ printf(" port %d %s %d", frp->frp_port,
+ pcmp1[frp->frp_cmp], frp->frp_top);
+ else
+ printf(" port %s %s", pcmp1[frp->frp_cmp],
+ portname(pr, frp->frp_port));
+}
+
+
+void printbuf(buf, len, zend)
+char *buf;
+int len, zend;
+{
+ char *s, c;
+ int i;
+
+ for (s = buf, i = len; i; i--) {
+ c = *s++;
+ if (isprint(c))
+ putchar(c);
+ else
+ printf("\\%03o", c);
+ if ((c == '\0') && zend)
+ break;
+ }
+}
+
+
+
+char *hostname(v, ip)
+int v;
+void *ip;
+{
+#ifdef USE_INET6
+ static char hostbuf[MAXHOSTNAMELEN+1];
+#endif
+ struct in_addr ipa;
+
+ if (v == 4) {
+ ipa.s_addr = *(u_32_t *)ip;
+ return inet_ntoa(ipa);
+ }
+#ifdef USE_INET6
+ (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1);
+ hostbuf[MAXHOSTNAMELEN] = '\0';
+ return hostbuf;
+#else
+ return "IPv6";
+#endif
+}
OpenPOWER on IntegriCloud