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