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