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