xref: /freebsd/sbin/ipf/ipsend/ipsopt.c (revision 51e16cb8fc536913f490ac6bc9c17e92ebd0411b)
141edb306SCy Schubert 
241edb306SCy Schubert /*
341edb306SCy Schubert  * Copyright (C) 2012 by Darren Reed.
441edb306SCy Schubert  *
541edb306SCy Schubert  * See the IPFILTER.LICENCE file for details on licencing.
641edb306SCy Schubert  *
741edb306SCy Schubert  */
841edb306SCy Schubert #include <sys/param.h>
941edb306SCy Schubert #include <sys/types.h>
1041edb306SCy Schubert #include <sys/time.h>
1141edb306SCy Schubert #include <sys/socket.h>
1241edb306SCy Schubert #include <netinet/in.h>
1341edb306SCy Schubert #include <netinet/in_systm.h>
1441edb306SCy Schubert #include <netinet/ip.h>
1541edb306SCy Schubert #include <stdio.h>
1641edb306SCy Schubert #include <string.h>
1741edb306SCy Schubert #include <stdlib.h>
1841edb306SCy Schubert #include <netinet/ip_var.h>
1941edb306SCy Schubert #include <netinet/tcp.h>
2041edb306SCy Schubert #include <arpa/inet.h>
2141edb306SCy Schubert #include "ipsend.h"
2241edb306SCy Schubert 
2341edb306SCy Schubert 
2441edb306SCy Schubert #ifndef	__P
2541edb306SCy Schubert #  define	__P(x)	x
2641edb306SCy Schubert #endif
2741edb306SCy Schubert 
2841edb306SCy Schubert 
2941edb306SCy Schubert struct ipopt_names ionames[] = {
3041edb306SCy Schubert 	{ IPOPT_EOL,	0x01,	1, "eol" },
3141edb306SCy Schubert 	{ IPOPT_NOP,	0x02,	1, "nop" },
3241edb306SCy Schubert 	{ IPOPT_RR,	0x04,	3, "rr" },	/* 1 route */
3341edb306SCy Schubert 	{ IPOPT_TS,	0x08,	8, "ts" },	/* 1 TS */
3441edb306SCy Schubert 	{ IPOPT_SECURITY, 0x08,	11, "sec-level" },
3541edb306SCy Schubert 	{ IPOPT_LSRR,	0x10,	7, "lsrr" },	/* 1 route */
3641edb306SCy Schubert 	{ IPOPT_SATID,	0x20,	4, "satid" },
3741edb306SCy Schubert 	{ IPOPT_SSRR,	0x40,	7, "ssrr" },	/* 1 route */
3841edb306SCy Schubert 	{ 0, 0, 0, NULL }	/* must be last */
3941edb306SCy Schubert };
4041edb306SCy Schubert 
4141edb306SCy Schubert struct	ipopt_names secnames[] = {
4241edb306SCy Schubert 	{ IPOPT_SECUR_UNCLASS,	0x0100,	0, "unclass" },
4341edb306SCy Schubert 	{ IPOPT_SECUR_CONFID,	0x0200,	0, "confid" },
4441edb306SCy Schubert 	{ IPOPT_SECUR_EFTO,	0x0400,	0, "efto" },
4541edb306SCy Schubert 	{ IPOPT_SECUR_MMMM,	0x0800,	0, "mmmm" },
4641edb306SCy Schubert 	{ IPOPT_SECUR_RESTR,	0x1000,	0, "restr" },
4741edb306SCy Schubert 	{ IPOPT_SECUR_SECRET,	0x2000,	0, "secret" },
4841edb306SCy Schubert 	{ IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" },
4941edb306SCy Schubert 	{ 0, 0, 0, NULL }	/* must be last */
5041edb306SCy Schubert };
5141edb306SCy Schubert 
5241edb306SCy Schubert 
ipseclevel(slevel)5341edb306SCy Schubert u_short ipseclevel(slevel)
5441edb306SCy Schubert 	char *slevel;
5541edb306SCy Schubert {
5641edb306SCy Schubert 	struct ipopt_names *so;
5741edb306SCy Schubert 
5841edb306SCy Schubert 	for (so = secnames; so->on_name; so++)
5941edb306SCy Schubert 		if (!strcasecmp(slevel, so->on_name))
6041edb306SCy Schubert 			break;
6141edb306SCy Schubert 
6241edb306SCy Schubert 	if (!so->on_name) {
6341edb306SCy Schubert 		fprintf(stderr, "no such security level: %s\n", slevel);
64*2582ae57SCy Schubert 		return (0);
6541edb306SCy Schubert 	}
66*2582ae57SCy Schubert 	return (so->on_value);
6741edb306SCy Schubert }
6841edb306SCy Schubert 
6941edb306SCy Schubert 
70efeb8bffSCy Schubert int
addipopt(char * op,struct ipopt_names * io,int len,char * class)71efeb8bffSCy Schubert addipopt(char *op, struct ipopt_names *io, int len, char *class)
7241edb306SCy Schubert {
7341edb306SCy Schubert 	struct in_addr ipadr;
7441edb306SCy Schubert 	int olen = len, srr = 0;
7541edb306SCy Schubert 	u_short val;
7641edb306SCy Schubert 	u_char lvl;
7741edb306SCy Schubert 	char *s = op, *t;
7841edb306SCy Schubert 
7941edb306SCy Schubert 	if ((len + io->on_siz) > 48) {
8041edb306SCy Schubert 		fprintf(stderr, "options too long\n");
81*2582ae57SCy Schubert 		return (0);
8241edb306SCy Schubert 	}
8341edb306SCy Schubert 	len += io->on_siz;
8441edb306SCy Schubert 	*op++ = io->on_value;
8541edb306SCy Schubert 	if (io->on_siz > 1) {
8641edb306SCy Schubert 		/*
8741edb306SCy Schubert 		 * Allow option to specify RR buffer length in bytes.
8841edb306SCy Schubert 		 */
8941edb306SCy Schubert 		if (io->on_value == IPOPT_RR) {
9041edb306SCy Schubert 			val = (class && *class) ? atoi(class) : 4;
9141edb306SCy Schubert 			*op++ = val + io->on_siz;
9241edb306SCy Schubert 			len += val;
9341edb306SCy Schubert 		} else
9441edb306SCy Schubert 			*op++ = io->on_siz;
9541edb306SCy Schubert 		if (io->on_value == IPOPT_TS)
9641edb306SCy Schubert 			*op++ = IPOPT_MINOFF + 1;
9741edb306SCy Schubert 		else
9841edb306SCy Schubert 			*op++ = IPOPT_MINOFF;
9941edb306SCy Schubert 
10041edb306SCy Schubert 		while (class && *class) {
10141edb306SCy Schubert 			t = NULL;
10241edb306SCy Schubert 			switch (io->on_value)
10341edb306SCy Schubert 			{
10441edb306SCy Schubert 			case IPOPT_SECURITY :
10541edb306SCy Schubert 				lvl = ipseclevel(class);
10641edb306SCy Schubert 				*(op - 1) = lvl;
10741edb306SCy Schubert 				break;
10841edb306SCy Schubert 			case IPOPT_LSRR :
10941edb306SCy Schubert 			case IPOPT_SSRR :
11041edb306SCy Schubert 				if ((t = strchr(class, ',')))
11141edb306SCy Schubert 					*t = '\0';
11241edb306SCy Schubert 				ipadr.s_addr = inet_addr(class);
11341edb306SCy Schubert 				srr++;
11441edb306SCy Schubert 				bcopy((char *)&ipadr, op, sizeof(ipadr));
11541edb306SCy Schubert 				op += sizeof(ipadr);
11641edb306SCy Schubert 				break;
11741edb306SCy Schubert 			case IPOPT_SATID :
11841edb306SCy Schubert 				val = atoi(class);
11941edb306SCy Schubert 				bcopy((char *)&val, op, 2);
12041edb306SCy Schubert 				break;
12141edb306SCy Schubert 			}
12241edb306SCy Schubert 
12341edb306SCy Schubert 			if (t)
12441edb306SCy Schubert 				*t++ = ',';
12541edb306SCy Schubert 			class = t;
12641edb306SCy Schubert 		}
12741edb306SCy Schubert 		if (srr)
12841edb306SCy Schubert 			s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr;
12941edb306SCy Schubert 		if (io->on_value == IPOPT_RR)
13041edb306SCy Schubert 			op += val;
13141edb306SCy Schubert 		else
13241edb306SCy Schubert 			op += io->on_siz - 3;
13341edb306SCy Schubert 	}
134*2582ae57SCy Schubert 	return (len - olen);
13541edb306SCy Schubert }
13641edb306SCy Schubert 
13741edb306SCy Schubert 
138efeb8bffSCy Schubert u_32_t
139efeb8bffSCy Schubert buildopts(char *cp, char *op, int len)
14041edb306SCy Schubert 	char *cp, *op;
14141edb306SCy Schubert 	int len;
14241edb306SCy Schubert {
14341edb306SCy Schubert 	struct ipopt_names *io;
14441edb306SCy Schubert 	u_32_t msk = 0;
14541edb306SCy Schubert 	char *s, *t;
14641edb306SCy Schubert 	int inc, lastop = -1;
14741edb306SCy Schubert 
14841edb306SCy Schubert 	for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) {
14941edb306SCy Schubert 		if ((t = strchr(s, '=')))
15041edb306SCy Schubert 			*t++ = '\0';
15141edb306SCy Schubert 		for (io = ionames; io->on_name; io++) {
15241edb306SCy Schubert 			if (strcasecmp(s, io->on_name) || (msk & io->on_bit))
15341edb306SCy Schubert 				continue;
15441edb306SCy Schubert 			lastop = io->on_value;
15541edb306SCy Schubert 			if ((inc = addipopt(op, io, len, t))) {
15641edb306SCy Schubert 				op += inc;
15741edb306SCy Schubert 				len += inc;
15841edb306SCy Schubert 			}
15941edb306SCy Schubert 			msk |= io->on_bit;
16041edb306SCy Schubert 			break;
16141edb306SCy Schubert 		}
16241edb306SCy Schubert 		if (!io->on_name) {
16341edb306SCy Schubert 			fprintf(stderr, "unknown IP option name %s\n", s);
164*2582ae57SCy Schubert 			return (0);
16541edb306SCy Schubert 		}
16641edb306SCy Schubert 	}
16741edb306SCy Schubert 
16841edb306SCy Schubert 	if (len & 3) {
16941edb306SCy Schubert 		while (len & 3) {
17041edb306SCy Schubert 			*op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP;
17141edb306SCy Schubert 			len++;
17241edb306SCy Schubert 		}
17341edb306SCy Schubert 	} else {
17441edb306SCy Schubert 		if (lastop != IPOPT_EOL) {
17541edb306SCy Schubert 			if (lastop == IPOPT_NOP)
17641edb306SCy Schubert 				*(op - 1) = IPOPT_EOL;
17741edb306SCy Schubert 			else {
17841edb306SCy Schubert 				*op++ = IPOPT_NOP;
17941edb306SCy Schubert 				*op++ = IPOPT_NOP;
18041edb306SCy Schubert 				*op++ = IPOPT_NOP;
18141edb306SCy Schubert 				*op = IPOPT_EOL;
18241edb306SCy Schubert 				len += 4;
18341edb306SCy Schubert 			}
18441edb306SCy Schubert 		}
18541edb306SCy Schubert 	}
186*2582ae57SCy Schubert 	return (len);
18741edb306SCy Schubert }
188