Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

#include "ipf.h"
#include <ctype.h>


typedef struct ipfopentry {
	int	ipoe_cmd;
	int	ipoe_nbasearg;
	int	ipoe_maxarg;
	int	ipoe_argsize;
	char	*ipoe_word;
} ipfopentry_t;

static ipfopentry_t opwords[17] = {
	{ IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" },
	{ IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" },
	{ IPF_EXP_IP_PR, 1, 0, 1, "ip.p" },
	{ IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" },
	{ IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" },
	{ IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" },
	{ IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" },
	{ IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" },
	{ IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" },
	{ IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" },
	{ IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" },
	{ IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" },
	{ IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" },
	{ IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" },
	{ IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" },
	{ IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" },
	{ -1, 0, 0, 0, NULL  }
};


int *
parseipfexpr(line, errorptr)
	char *line;
	char **errorptr;
{
	int not, items, asize, *oplist, osize, i;
	char *temp, *arg, *s, *t, *ops, *error;
	ipfopentry_t *e;
	ipfexp_t *ipfe;

	asize = 0;
	error = NULL;
	oplist = NULL;

	temp = strdup(line);
	if (temp == NULL) {
		error = "strdup failed";
		goto parseerror;
	}

	/*
	 * Eliminate any white spaces to make parsing easier.
	 */
	for (s = temp; *s != '\0'; ) {
		if (ISSPACE(*s))
			strcpy(s, s + 1);
		else
			s++;
	}

	/*
	 * Parse the string.
	 * It should be sets of "ip.dst=1.2.3.4/32;" things.
	 * There must be a "=" or "!=" and it must end in ";".
	 */
	if (temp[strlen(temp) - 1] != ';') {
		error = "last character not ';'";
		goto parseerror;
	}

	/*
	 * Work through the list of complete operands present.
	 */
	for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) {
		arg = strchr(ops, '=');
		if ((arg < ops + 2) || (arg == NULL)) {
			error = "bad 'arg' vlaue";
			goto parseerror;
		}

		if (*(arg - 1) == '!') {
			*(arg - 1) = '\0';
			not = 1;
		} else {
			not = 0;
		}
		*arg++ = '\0';


		for (e = opwords; e->ipoe_word; e++) {
			if (strcmp(ops, e->ipoe_word) == 0)
				break;
		}
		if (e->ipoe_word == NULL) {
			error = malloc(32);
			if (error != NULL) {
				sprintf(error, "keyword (%.10s) not found",
					ops);
			}
			goto parseerror;
		}

		/*
		 * Count the number of commas so we know how big to
		 * build the array
		 */
		for (s = arg, items = 1; *s != '\0'; s++)
			if (*s == ',')
				items++;

		if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) {
			error = "too many items";
			goto parseerror;
		}

		/*
		 * osize will mark the end of where we have filled up to
		 * and is thus where we start putting new data.
		 */
		osize = asize;
		asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize);
		if (oplist == NULL)
			oplist = calloc(asize + 2, sizeof(int));
		else
			oplist = reallocarray(oplist, asize + 2, sizeof(int));
		if (oplist == NULL) {
			error = "oplist alloc failed";
			goto parseerror;
		}
		ipfe = (ipfexp_t *)(oplist + osize);
		osize += 4;
		ipfe->ipfe_cmd = e->ipoe_cmd;
		ipfe->ipfe_not = not;
		ipfe->ipfe_narg = items * e->ipoe_nbasearg;
		ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize;
		ipfe->ipfe_size += 4;

		for (s = arg; (*s != '\0') && (osize < asize); s = t) {
			/*
			 * Look for the end of this arg or the ',' to say
			 * there is another following.
			 */
			for (t = s; (*t != '\0') && (*t != ','); t++)
				;
			if (*t == ',')
				*t++ = '\0';

			if (!strcasecmp(ops, "ip.addr") ||
			    !strcasecmp(ops, "ip.src") ||
			    !strcasecmp(ops, "ip.dst")) {
				i6addr_t mask, addr;
				char *delim;

				delim = strchr(s, '/');
				if (delim != NULL) {
					*delim++ = '\0';
					if (genmask(AF_INET, delim,
						    &mask) == -1) {
						error = "genmask failed";
						goto parseerror;
					}
				} else {
					mask.in4.s_addr = 0xffffffff;
				}
				if (gethost(AF_INET, s, &addr) == -1) {
					error = "gethost failed";
					goto parseerror;
				}

				oplist[osize++] = addr.in4.s_addr;
				oplist[osize++] = mask.in4.s_addr;

#ifdef USE_INET6
			} else if (!strcasecmp(ops, "ip6.addr") ||
			    !strcasecmp(ops, "ip6.src") ||
			    !strcasecmp(ops, "ip6.dst")) {
				i6addr_t mask, addr;
				char *delim;

				delim = strchr(s, '/');
				if (delim != NULL) {
					*delim++ = '\0';
					if (genmask(AF_INET6, delim,
						    &mask) == -1) {
						error = "genmask failed";
						goto parseerror;
					}
				} else {
					mask.i6[0] = 0xffffffff;
					mask.i6[1] = 0xffffffff;
					mask.i6[2] = 0xffffffff;
					mask.i6[3] = 0xffffffff;
				}
				if (gethost(AF_INET6, s, &addr) == -1) {
					error = "gethost failed";
					goto parseerror;
				}

				oplist[osize++] = addr.i6[0];
				oplist[osize++] = addr.i6[1];
				oplist[osize++] = addr.i6[2];
				oplist[osize++] = addr.i6[3];
				oplist[osize++] = mask.i6[0];
				oplist[osize++] = mask.i6[1];
				oplist[osize++] = mask.i6[2];
				oplist[osize++] = mask.i6[3];
#endif

			} else if (!strcasecmp(ops, "ip.p")) {
				int p;

				p = getproto(s);
				if (p == -1)
					goto parseerror;
				oplist[osize++] = p;

			} else if (!strcasecmp(ops, "tcp.flags")) {
				u_32_t mask, flags;
				char *delim;

				delim = strchr(s, '/');
				if (delim != NULL) {
					*delim++ = '\0';
					mask = tcpflags(delim);
				} else {
					mask = 0xff;
				}
				flags = tcpflags(s);

				oplist[osize++] = flags;
				oplist[osize++] = mask;


			} else if (!strcasecmp(ops, "tcp.port") ||
			    !strcasecmp(ops, "tcp.sport") ||
			    !strcasecmp(ops, "tcp.dport") ||
			    !strcasecmp(ops, "udp.port") ||
			    !strcasecmp(ops, "udp.sport") ||
			    !strcasecmp(ops, "udp.dport")) {
				char proto[4];
				u_short port;

				strncpy(proto, ops, 3);
				proto[3] = '\0';
				if (getport(NULL, s, &port, proto) == -1)
					goto parseerror;
				oplist[osize++] = port;

			} else if (!strcasecmp(ops, "tcp.state")) {
				oplist[osize++] = atoi(s);

			} else {
				error = "unknown word";
				goto parseerror;
			}
		}
	}

	free(temp);

	if (errorptr != NULL)
		*errorptr = NULL;

	for (i = asize; i > 0; i--)
		oplist[i] = oplist[i - 1];

	oplist[0] = asize + 2;
	oplist[asize + 1] = IPF_EXP_END;

	return oplist;

parseerror:
	if (errorptr != NULL)
		*errorptr = error;
	if (oplist != NULL)
		free(oplist);
	if (temp != NULL)
		free(temp);
	return NULL;
}