ipsopt.c revision 110917
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.4 2002/12/06 11:40:35 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		*op++ = IPOPT_MINOFF;
102
103		while (class && *class) {
104			t = NULL;
105			switch (io->on_value)
106			{
107			case IPOPT_SECURITY :
108				lvl = seclevel(class);
109				*(op - 1) = lvl;
110				break;
111			case IPOPT_LSRR :
112			case IPOPT_SSRR :
113				if ((t = strchr(class, ',')))
114					*t = '\0';
115				ipadr.s_addr = inet_addr(class);
116				srr++;
117				bcopy((char *)&ipadr, op, sizeof(ipadr));
118				op += sizeof(ipadr);
119				break;
120			case IPOPT_SATID :
121				val = atoi(class);
122				bcopy((char *)&val, op, 2);
123				break;
124			}
125
126			if (t)
127				*t++ = ',';
128			class = t;
129		}
130		if (srr)
131			s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr;
132		if (io->on_value == IPOPT_RR)
133			op += val;
134		else
135			op += io->on_siz - 3;
136	}
137	return len - olen;
138}
139
140
141u_32_t buildopts(cp, op, len)
142char *cp, *op;
143int len;
144{
145	struct ipopt_names *io;
146	u_32_t msk = 0;
147	char *s, *t;
148	int inc, lastop = -1;
149
150	for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) {
151		if ((t = strchr(s, '=')))
152			*t++ = '\0';
153		for (io = ionames; io->on_name; io++) {
154			if (strcasecmp(s, io->on_name) || (msk & io->on_bit))
155				continue;
156			lastop = io->on_value;
157			if ((inc = addipopt(op, io, len, t))) {
158				op += inc;
159				len += inc;
160			}
161			msk |= io->on_bit;
162			break;
163		}
164		if (!io->on_name) {
165			fprintf(stderr, "unknown IP option name %s\n", s);
166			return 0;
167		}
168	}
169
170	if (len & 3) {
171		while (len & 3) {
172			*op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP;
173			len++;
174		}
175	} else {
176		if (lastop != IPOPT_EOL) {
177			if (lastop == IPOPT_NOP)
178				*(op - 1) = IPOPT_EOL;
179			else {
180				*op++ = IPOPT_NOP;
181				*op++ = IPOPT_NOP;
182				*op++ = IPOPT_NOP;
183				*op = IPOPT_EOL;
184				len += 4;
185			}
186		}
187	}
188	return len;
189}
190