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