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