xref: /netbsd-src/external/bsd/ipf/dist/ipsend/ipsopt.c (revision 07967fb18af5b87d2d477c5b3e1e438bf0c293fb)
1*07967fb1Smrg /*	$NetBSD: ipsopt.c,v 1.3 2018/02/04 08:19:42 mrg Exp $	*/
2bc4097aaSchristos 
3bc4097aaSchristos /*
4c9d5dc6cSdarrenr  * Copyright (C) 2012 by Darren Reed.
5bc4097aaSchristos  *
6bc4097aaSchristos  * See the IPFILTER.LICENCE file for details on licencing.
7bc4097aaSchristos  *
8bc4097aaSchristos  */
9bc4097aaSchristos #if !defined(lint)
10*07967fb1Smrg static __attribute__((__used__)) const char sccsid[] = "@(#)ipsopt.c	1.2 1/11/96 (C)1995 Darren Reed";
11*07967fb1Smrg static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipsopt.c,v 1.1.1.2 2012/07/22 13:44:36 darrenr Exp $";
12bc4097aaSchristos #endif
13bc4097aaSchristos #include <sys/param.h>
14bc4097aaSchristos #include <sys/types.h>
15bc4097aaSchristos #include <sys/time.h>
16bc4097aaSchristos #include <sys/socket.h>
17bc4097aaSchristos #include <netinet/in.h>
18bc4097aaSchristos #include <netinet/in_systm.h>
19bc4097aaSchristos #include <netinet/ip.h>
20bc4097aaSchristos #include <stdio.h>
21bc4097aaSchristos #include <string.h>
22bc4097aaSchristos #include <stdlib.h>
23bc4097aaSchristos #ifndef	linux
24bc4097aaSchristos #include <netinet/ip_var.h>
25bc4097aaSchristos #endif
26bc4097aaSchristos #include <netinet/tcp.h>
27bc4097aaSchristos #include <arpa/inet.h>
28bc4097aaSchristos #include "ipsend.h"
29bc4097aaSchristos 
30bc4097aaSchristos 
31bc4097aaSchristos #ifndef	__P
32bc4097aaSchristos # ifdef	__STDC__
33bc4097aaSchristos #  define	__P(x)	x
34bc4097aaSchristos # else
35bc4097aaSchristos #  define	__P(x)	()
36bc4097aaSchristos # endif
37bc4097aaSchristos #endif
38bc4097aaSchristos 
39bc4097aaSchristos 
40bc4097aaSchristos struct ipopt_names ionames[] = {
41bc4097aaSchristos 	{ IPOPT_EOL,	0x01,	1, "eol" },
42bc4097aaSchristos 	{ IPOPT_NOP,	0x02,	1, "nop" },
43bc4097aaSchristos 	{ IPOPT_RR,	0x04,	3, "rr" },	/* 1 route */
44bc4097aaSchristos 	{ IPOPT_TS,	0x08,	8, "ts" },	/* 1 TS */
45bc4097aaSchristos 	{ IPOPT_SECURITY, 0x08,	11, "sec-level" },
46bc4097aaSchristos 	{ IPOPT_LSRR,	0x10,	7, "lsrr" },	/* 1 route */
47bc4097aaSchristos 	{ IPOPT_SATID,	0x20,	4, "satid" },
48bc4097aaSchristos 	{ IPOPT_SSRR,	0x40,	7, "ssrr" },	/* 1 route */
49bc4097aaSchristos 	{ 0, 0, 0, NULL }	/* must be last */
50bc4097aaSchristos };
51bc4097aaSchristos 
52bc4097aaSchristos struct	ipopt_names secnames[] = {
53bc4097aaSchristos 	{ IPOPT_SECUR_UNCLASS,	0x0100,	0, "unclass" },
54bc4097aaSchristos 	{ IPOPT_SECUR_CONFID,	0x0200,	0, "confid" },
55bc4097aaSchristos 	{ IPOPT_SECUR_EFTO,	0x0400,	0, "efto" },
56bc4097aaSchristos 	{ IPOPT_SECUR_MMMM,	0x0800,	0, "mmmm" },
57bc4097aaSchristos 	{ IPOPT_SECUR_RESTR,	0x1000,	0, "restr" },
58bc4097aaSchristos 	{ IPOPT_SECUR_SECRET,	0x2000,	0, "secret" },
59bc4097aaSchristos 	{ IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" },
60bc4097aaSchristos 	{ 0, 0, 0, NULL }	/* must be last */
61bc4097aaSchristos };
62bc4097aaSchristos 
63bc4097aaSchristos 
ipseclevel(slevel)64bc4097aaSchristos u_short ipseclevel(slevel)
65bc4097aaSchristos 	char *slevel;
66bc4097aaSchristos {
67bc4097aaSchristos 	struct ipopt_names *so;
68bc4097aaSchristos 
69bc4097aaSchristos 	for (so = secnames; so->on_name; so++)
70bc4097aaSchristos 		if (!strcasecmp(slevel, so->on_name))
71bc4097aaSchristos 			break;
72bc4097aaSchristos 
73bc4097aaSchristos 	if (!so->on_name) {
74bc4097aaSchristos 		fprintf(stderr, "no such security level: %s\n", slevel);
75bc4097aaSchristos 		return 0;
76bc4097aaSchristos 	}
77bc4097aaSchristos 	return so->on_value;
78bc4097aaSchristos }
79bc4097aaSchristos 
80bc4097aaSchristos 
addipopt(op,io,len,class)81bc4097aaSchristos int addipopt(op, io, len, class)
82bc4097aaSchristos 	char *op;
83bc4097aaSchristos 	struct ipopt_names *io;
84bc4097aaSchristos 	int len;
85bc4097aaSchristos 	char *class;
86bc4097aaSchristos {
87bc4097aaSchristos 	struct in_addr ipadr;
88bc4097aaSchristos 	int olen = len, srr = 0;
89bc4097aaSchristos 	u_short val;
90bc4097aaSchristos 	u_char lvl;
91bc4097aaSchristos 	char *s = op, *t;
92bc4097aaSchristos 
93bc4097aaSchristos 	if ((len + io->on_siz) > 48) {
94bc4097aaSchristos 		fprintf(stderr, "options too long\n");
95bc4097aaSchristos 		return 0;
96bc4097aaSchristos 	}
97bc4097aaSchristos 	len += io->on_siz;
98bc4097aaSchristos 	*op++ = io->on_value;
99bc4097aaSchristos 	if (io->on_siz > 1) {
100bc4097aaSchristos 		/*
101bc4097aaSchristos 		 * Allow option to specify RR buffer length in bytes.
102bc4097aaSchristos 		 */
103bc4097aaSchristos 		if (io->on_value == IPOPT_RR) {
104bc4097aaSchristos 			val = (class && *class) ? atoi(class) : 4;
105bc4097aaSchristos 			*op++ = val + io->on_siz;
106bc4097aaSchristos 			len += val;
107bc4097aaSchristos 		} else
108bc4097aaSchristos 			*op++ = io->on_siz;
109bc4097aaSchristos 		if (io->on_value == IPOPT_TS)
110bc4097aaSchristos 			*op++ = IPOPT_MINOFF + 1;
111bc4097aaSchristos 		else
112bc4097aaSchristos 			*op++ = IPOPT_MINOFF;
113bc4097aaSchristos 
114bc4097aaSchristos 		while (class && *class) {
115bc4097aaSchristos 			t = NULL;
116bc4097aaSchristos 			switch (io->on_value)
117bc4097aaSchristos 			{
118bc4097aaSchristos 			case IPOPT_SECURITY :
119bc4097aaSchristos 				lvl = ipseclevel(class);
120bc4097aaSchristos 				*(op - 1) = lvl;
121bc4097aaSchristos 				break;
122bc4097aaSchristos 			case IPOPT_LSRR :
123bc4097aaSchristos 			case IPOPT_SSRR :
124bc4097aaSchristos 				if ((t = strchr(class, ',')))
125bc4097aaSchristos 					*t = '\0';
126bc4097aaSchristos 				ipadr.s_addr = inet_addr(class);
127bc4097aaSchristos 				srr++;
128bc4097aaSchristos 				bcopy((char *)&ipadr, op, sizeof(ipadr));
129bc4097aaSchristos 				op += sizeof(ipadr);
130bc4097aaSchristos 				break;
131bc4097aaSchristos 			case IPOPT_SATID :
132bc4097aaSchristos 				val = atoi(class);
133bc4097aaSchristos 				bcopy((char *)&val, op, 2);
134bc4097aaSchristos 				break;
135bc4097aaSchristos 			}
136bc4097aaSchristos 
137bc4097aaSchristos 			if (t)
138bc4097aaSchristos 				*t++ = ',';
139bc4097aaSchristos 			class = t;
140bc4097aaSchristos 		}
141bc4097aaSchristos 		if (srr)
142bc4097aaSchristos 			s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr;
143bc4097aaSchristos 		if (io->on_value == IPOPT_RR)
144bc4097aaSchristos 			op += val;
145bc4097aaSchristos 		else
146bc4097aaSchristos 			op += io->on_siz - 3;
147bc4097aaSchristos 	}
148bc4097aaSchristos 	return len - olen;
149bc4097aaSchristos }
150bc4097aaSchristos 
151bc4097aaSchristos 
buildopts(cp,op,len)152bc4097aaSchristos u_32_t buildopts(cp, op, len)
153bc4097aaSchristos 	char *cp, *op;
154bc4097aaSchristos 	int len;
155bc4097aaSchristos {
156bc4097aaSchristos 	struct ipopt_names *io;
157bc4097aaSchristos 	u_32_t msk = 0;
158bc4097aaSchristos 	char *s, *t;
159bc4097aaSchristos 	int inc, lastop = -1;
160bc4097aaSchristos 
161bc4097aaSchristos 	for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) {
162bc4097aaSchristos 		if ((t = strchr(s, '=')))
163bc4097aaSchristos 			*t++ = '\0';
164bc4097aaSchristos 		for (io = ionames; io->on_name; io++) {
165bc4097aaSchristos 			if (strcasecmp(s, io->on_name) || (msk & io->on_bit))
166bc4097aaSchristos 				continue;
167bc4097aaSchristos 			lastop = io->on_value;
168bc4097aaSchristos 			if ((inc = addipopt(op, io, len, t))) {
169bc4097aaSchristos 				op += inc;
170bc4097aaSchristos 				len += inc;
171bc4097aaSchristos 			}
172bc4097aaSchristos 			msk |= io->on_bit;
173bc4097aaSchristos 			break;
174bc4097aaSchristos 		}
175bc4097aaSchristos 		if (!io->on_name) {
176bc4097aaSchristos 			fprintf(stderr, "unknown IP option name %s\n", s);
177bc4097aaSchristos 			return 0;
178bc4097aaSchristos 		}
179bc4097aaSchristos 	}
180bc4097aaSchristos 
181bc4097aaSchristos 	if (len & 3) {
182bc4097aaSchristos 		while (len & 3) {
183bc4097aaSchristos 			*op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP;
184bc4097aaSchristos 			len++;
185bc4097aaSchristos 		}
186bc4097aaSchristos 	} else {
187bc4097aaSchristos 		if (lastop != IPOPT_EOL) {
188bc4097aaSchristos 			if (lastop == IPOPT_NOP)
189bc4097aaSchristos 				*(op - 1) = IPOPT_EOL;
190bc4097aaSchristos 			else {
191bc4097aaSchristos 				*op++ = IPOPT_NOP;
192bc4097aaSchristos 				*op++ = IPOPT_NOP;
193bc4097aaSchristos 				*op++ = IPOPT_NOP;
194bc4097aaSchristos 				*op = IPOPT_EOL;
195bc4097aaSchristos 				len += 4;
196bc4097aaSchristos 			}
197bc4097aaSchristos 		}
198bc4097aaSchristos 	}
199bc4097aaSchristos 	return len;
200bc4097aaSchristos }
201