141edb306SCy Schubert
241edb306SCy Schubert /*
341edb306SCy Schubert * Copyright (C) 2012 by Darren Reed.
441edb306SCy Schubert *
541edb306SCy Schubert * See the IPFILTER.LICENCE file for details on licencing.
641edb306SCy Schubert *
741edb306SCy Schubert */
841edb306SCy Schubert #include <sys/param.h>
941edb306SCy Schubert #include <sys/types.h>
1041edb306SCy Schubert #include <sys/time.h>
1141edb306SCy Schubert #include <sys/socket.h>
1241edb306SCy Schubert #include <netinet/in.h>
1341edb306SCy Schubert #include <netinet/in_systm.h>
1441edb306SCy Schubert #include <netinet/ip.h>
1541edb306SCy Schubert #include <stdio.h>
1641edb306SCy Schubert #include <string.h>
1741edb306SCy Schubert #include <stdlib.h>
1841edb306SCy Schubert #include <netinet/ip_var.h>
1941edb306SCy Schubert #include <netinet/tcp.h>
2041edb306SCy Schubert #include <arpa/inet.h>
2141edb306SCy Schubert #include "ipsend.h"
2241edb306SCy Schubert
2341edb306SCy Schubert
2441edb306SCy Schubert #ifndef __P
2541edb306SCy Schubert # define __P(x) x
2641edb306SCy Schubert #endif
2741edb306SCy Schubert
2841edb306SCy Schubert
2941edb306SCy Schubert struct ipopt_names ionames[] = {
3041edb306SCy Schubert { IPOPT_EOL, 0x01, 1, "eol" },
3141edb306SCy Schubert { IPOPT_NOP, 0x02, 1, "nop" },
3241edb306SCy Schubert { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */
3341edb306SCy Schubert { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */
3441edb306SCy Schubert { IPOPT_SECURITY, 0x08, 11, "sec-level" },
3541edb306SCy Schubert { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */
3641edb306SCy Schubert { IPOPT_SATID, 0x20, 4, "satid" },
3741edb306SCy Schubert { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */
3841edb306SCy Schubert { 0, 0, 0, NULL } /* must be last */
3941edb306SCy Schubert };
4041edb306SCy Schubert
4141edb306SCy Schubert struct ipopt_names secnames[] = {
4241edb306SCy Schubert { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" },
4341edb306SCy Schubert { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" },
4441edb306SCy Schubert { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" },
4541edb306SCy Schubert { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" },
4641edb306SCy Schubert { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" },
4741edb306SCy Schubert { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" },
4841edb306SCy Schubert { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" },
4941edb306SCy Schubert { 0, 0, 0, NULL } /* must be last */
5041edb306SCy Schubert };
5141edb306SCy Schubert
5241edb306SCy Schubert
ipseclevel(slevel)5341edb306SCy Schubert u_short ipseclevel(slevel)
5441edb306SCy Schubert char *slevel;
5541edb306SCy Schubert {
5641edb306SCy Schubert struct ipopt_names *so;
5741edb306SCy Schubert
5841edb306SCy Schubert for (so = secnames; so->on_name; so++)
5941edb306SCy Schubert if (!strcasecmp(slevel, so->on_name))
6041edb306SCy Schubert break;
6141edb306SCy Schubert
6241edb306SCy Schubert if (!so->on_name) {
6341edb306SCy Schubert fprintf(stderr, "no such security level: %s\n", slevel);
64*2582ae57SCy Schubert return (0);
6541edb306SCy Schubert }
66*2582ae57SCy Schubert return (so->on_value);
6741edb306SCy Schubert }
6841edb306SCy Schubert
6941edb306SCy Schubert
70efeb8bffSCy Schubert int
addipopt(char * op,struct ipopt_names * io,int len,char * class)71efeb8bffSCy Schubert addipopt(char *op, struct ipopt_names *io, int len, char *class)
7241edb306SCy Schubert {
7341edb306SCy Schubert struct in_addr ipadr;
7441edb306SCy Schubert int olen = len, srr = 0;
7541edb306SCy Schubert u_short val;
7641edb306SCy Schubert u_char lvl;
7741edb306SCy Schubert char *s = op, *t;
7841edb306SCy Schubert
7941edb306SCy Schubert if ((len + io->on_siz) > 48) {
8041edb306SCy Schubert fprintf(stderr, "options too long\n");
81*2582ae57SCy Schubert return (0);
8241edb306SCy Schubert }
8341edb306SCy Schubert len += io->on_siz;
8441edb306SCy Schubert *op++ = io->on_value;
8541edb306SCy Schubert if (io->on_siz > 1) {
8641edb306SCy Schubert /*
8741edb306SCy Schubert * Allow option to specify RR buffer length in bytes.
8841edb306SCy Schubert */
8941edb306SCy Schubert if (io->on_value == IPOPT_RR) {
9041edb306SCy Schubert val = (class && *class) ? atoi(class) : 4;
9141edb306SCy Schubert *op++ = val + io->on_siz;
9241edb306SCy Schubert len += val;
9341edb306SCy Schubert } else
9441edb306SCy Schubert *op++ = io->on_siz;
9541edb306SCy Schubert if (io->on_value == IPOPT_TS)
9641edb306SCy Schubert *op++ = IPOPT_MINOFF + 1;
9741edb306SCy Schubert else
9841edb306SCy Schubert *op++ = IPOPT_MINOFF;
9941edb306SCy Schubert
10041edb306SCy Schubert while (class && *class) {
10141edb306SCy Schubert t = NULL;
10241edb306SCy Schubert switch (io->on_value)
10341edb306SCy Schubert {
10441edb306SCy Schubert case IPOPT_SECURITY :
10541edb306SCy Schubert lvl = ipseclevel(class);
10641edb306SCy Schubert *(op - 1) = lvl;
10741edb306SCy Schubert break;
10841edb306SCy Schubert case IPOPT_LSRR :
10941edb306SCy Schubert case IPOPT_SSRR :
11041edb306SCy Schubert if ((t = strchr(class, ',')))
11141edb306SCy Schubert *t = '\0';
11241edb306SCy Schubert ipadr.s_addr = inet_addr(class);
11341edb306SCy Schubert srr++;
11441edb306SCy Schubert bcopy((char *)&ipadr, op, sizeof(ipadr));
11541edb306SCy Schubert op += sizeof(ipadr);
11641edb306SCy Schubert break;
11741edb306SCy Schubert case IPOPT_SATID :
11841edb306SCy Schubert val = atoi(class);
11941edb306SCy Schubert bcopy((char *)&val, op, 2);
12041edb306SCy Schubert break;
12141edb306SCy Schubert }
12241edb306SCy Schubert
12341edb306SCy Schubert if (t)
12441edb306SCy Schubert *t++ = ',';
12541edb306SCy Schubert class = t;
12641edb306SCy Schubert }
12741edb306SCy Schubert if (srr)
12841edb306SCy Schubert s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr;
12941edb306SCy Schubert if (io->on_value == IPOPT_RR)
13041edb306SCy Schubert op += val;
13141edb306SCy Schubert else
13241edb306SCy Schubert op += io->on_siz - 3;
13341edb306SCy Schubert }
134*2582ae57SCy Schubert return (len - olen);
13541edb306SCy Schubert }
13641edb306SCy Schubert
13741edb306SCy Schubert
138efeb8bffSCy Schubert u_32_t
139efeb8bffSCy Schubert buildopts(char *cp, char *op, int len)
14041edb306SCy Schubert char *cp, *op;
14141edb306SCy Schubert int len;
14241edb306SCy Schubert {
14341edb306SCy Schubert struct ipopt_names *io;
14441edb306SCy Schubert u_32_t msk = 0;
14541edb306SCy Schubert char *s, *t;
14641edb306SCy Schubert int inc, lastop = -1;
14741edb306SCy Schubert
14841edb306SCy Schubert for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) {
14941edb306SCy Schubert if ((t = strchr(s, '=')))
15041edb306SCy Schubert *t++ = '\0';
15141edb306SCy Schubert for (io = ionames; io->on_name; io++) {
15241edb306SCy Schubert if (strcasecmp(s, io->on_name) || (msk & io->on_bit))
15341edb306SCy Schubert continue;
15441edb306SCy Schubert lastop = io->on_value;
15541edb306SCy Schubert if ((inc = addipopt(op, io, len, t))) {
15641edb306SCy Schubert op += inc;
15741edb306SCy Schubert len += inc;
15841edb306SCy Schubert }
15941edb306SCy Schubert msk |= io->on_bit;
16041edb306SCy Schubert break;
16141edb306SCy Schubert }
16241edb306SCy Schubert if (!io->on_name) {
16341edb306SCy Schubert fprintf(stderr, "unknown IP option name %s\n", s);
164*2582ae57SCy Schubert return (0);
16541edb306SCy Schubert }
16641edb306SCy Schubert }
16741edb306SCy Schubert
16841edb306SCy Schubert if (len & 3) {
16941edb306SCy Schubert while (len & 3) {
17041edb306SCy Schubert *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP;
17141edb306SCy Schubert len++;
17241edb306SCy Schubert }
17341edb306SCy Schubert } else {
17441edb306SCy Schubert if (lastop != IPOPT_EOL) {
17541edb306SCy Schubert if (lastop == IPOPT_NOP)
17641edb306SCy Schubert *(op - 1) = IPOPT_EOL;
17741edb306SCy Schubert else {
17841edb306SCy Schubert *op++ = IPOPT_NOP;
17941edb306SCy Schubert *op++ = IPOPT_NOP;
18041edb306SCy Schubert *op++ = IPOPT_NOP;
18141edb306SCy Schubert *op = IPOPT_EOL;
18241edb306SCy Schubert len += 4;
18341edb306SCy Schubert }
18441edb306SCy Schubert }
18541edb306SCy Schubert }
186*2582ae57SCy Schubert return (len);
18741edb306SCy Schubert }
188