ipsopt.c revision 130887
118334Speter/*
218334Speter * Copyright (C) 1995-1998 by Darren Reed.
318334Speter *
418334Speter * See the IPFILTER.LICENCE file for details on licencing.
518334Speter */
618334Speter#if defined(__sgi) && (IRIX > 602)
718334Speter# include <sys/ptimers.h>
818334Speter#endif
918334Speter#include <sys/param.h>
1018334Speter#include <stdio.h>
1118334Speter#include <string.h>
1218334Speter#include <stdlib.h>
1318334Speter#include <sys/types.h>
1418334Speter#include <sys/time.h>
1518334Speter#include <sys/socket.h>
1618334Speter#include <netinet/in.h>
1718334Speter#include <netinet/in_systm.h>
1818334Speter#include <netinet/ip.h>
1918334Speter#ifndef	linux
2018334Speter#include <netinet/ip_var.h>
2118334Speter#endif
2218334Speter#include <netinet/tcp.h>
2318334Speter#include <arpa/inet.h>
2418334Speter#include "ipsend.h"
2518334Speter
2618334Speter#if !defined(lint)
2718334Speterstatic const char sccsid[] = "@(#)ipsopt.c	1.2 1/11/96 (C)1995 Darren Reed";
2818334Speterstatic const char rcsid[] = "@(#)$Id: ipsopt.c,v 2.1.4.5 2004/04/10 11:50:52 darrenr Exp $";
2918334Speter#endif
3018334Speter
3118334Speter
3218334Speterstruct ipopt_names ionames[] = {
3318334Speter	{ IPOPT_EOL,	0x01,	1, "eol" },
3418334Speter	{ IPOPT_NOP,	0x02,	1, "nop" },
3518334Speter	{ IPOPT_RR,	0x04,	3, "rr" },	/* 1 route */
3618334Speter	{ IPOPT_TS,	0x08,	8, "ts" },	/* 1 TS */
3718334Speter	{ IPOPT_SECURITY, 0x08,	11, "sec-level" },
3818334Speter	{ IPOPT_LSRR,	0x10,	7, "lsrr" },	/* 1 route */
3918334Speter	{ IPOPT_SATID,	0x20,	4, "satid" },
4018334Speter	{ IPOPT_SSRR,	0x40,	7, "ssrr" },	/* 1 route */
4118334Speter	{ 0, 0, 0, NULL }	/* must be last */
4218334Speter};
4318334Speter
4418334Speterstruct	ipopt_names secnames[] = {
4518334Speter	{ IPOPT_SECUR_UNCLASS,	0x0100,	0, "unclass" },
4618334Speter	{ IPOPT_SECUR_CONFID,	0x0200,	0, "confid" },
4718334Speter	{ IPOPT_SECUR_EFTO,	0x0400,	0, "efto" },
4818334Speter	{ IPOPT_SECUR_MMMM,	0x0800,	0, "mmmm" },
4918334Speter	{ IPOPT_SECUR_RESTR,	0x1000,	0, "restr" },
5018334Speter	{ IPOPT_SECUR_SECRET,	0x2000,	0, "secret" },
5118334Speter	{ IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" },
5218334Speter	{ 0, 0, 0, NULL }	/* must be last */
5318334Speter};
5418334Speter
5518334Speter
5618334Speteru_short seclevel(slevel)
5718334Speterchar *slevel;
5818334Speter{
5918334Speter	struct ipopt_names *so;
6018334Speter
6118334Speter	for (so = secnames; so->on_name; so++)
6218334Speter		if (!strcasecmp(slevel, so->on_name))
6318334Speter			break;
6418334Speter
6518334Speter	if (!so->on_name) {
6618334Speter		fprintf(stderr, "no such security level: %s\n", slevel);
6718334Speter		return 0;
6818334Speter	}
6918334Speter	return so->on_value;
7018334Speter}
7118334Speter
7218334Speter
7318334Speterint addipopt(op, io, len, class)
7418334Speterchar *op;
7518334Speterstruct ipopt_names *io;
7618334Speterint len;
7718334Speterchar *class;
7818334Speter{
7918334Speter	struct in_addr ipadr;
8018334Speter	int olen = len, srr = 0;
8118334Speter	u_short val;
8218334Speter	u_char lvl;
8318334Speter	char *s = op, *t;
8418334Speter
8518334Speter	if ((len + io->on_siz) > 48) {
8618334Speter		fprintf(stderr, "options too long\n");
8718334Speter		return 0;
8818334Speter	}
8918334Speter	len += io->on_siz;
9018334Speter	*op++ = io->on_value;
9118334Speter	if (io->on_siz > 1) {
9218334Speter		/*
9318334Speter		 * Allow option to specify RR buffer length in bytes.
9418334Speter		 */
9518334Speter		if (io->on_value == IPOPT_RR) {
9618334Speter			val = (class && *class) ? atoi(class) : 4;
9718334Speter			*op++ = val + io->on_siz;
9818334Speter			len += val;
9918334Speter		} else
10018334Speter			*op++ = io->on_siz;
10118334Speter		if (io->on_value == IPOPT_TS)
10218334Speter			*op++ = IPOPT_MINOFF + 1;
10318334Speter		else
10418334Speter			*op++ = IPOPT_MINOFF;
10518334Speter
10618334Speter		while (class && *class) {
10718334Speter			t = NULL;
10818334Speter			switch (io->on_value)
10918334Speter			{
11018334Speter			case IPOPT_SECURITY :
11118334Speter				lvl = seclevel(class);
11218334Speter				*(op - 1) = lvl;
11318334Speter				break;
11418334Speter			case IPOPT_LSRR :
11518334Speter			case IPOPT_SSRR :
11618334Speter				if ((t = strchr(class, ',')))
11718334Speter					*t = '\0';
11818334Speter				ipadr.s_addr = inet_addr(class);
11918334Speter				srr++;
12018334Speter				bcopy((char *)&ipadr, op, sizeof(ipadr));
12118334Speter				op += sizeof(ipadr);
12218334Speter				break;
12318334Speter			case IPOPT_SATID :
12418334Speter				val = atoi(class);
12518334Speter				bcopy((char *)&val, op, 2);
12618334Speter				break;
12718334Speter			}
12818334Speter
12918334Speter			if (t)
13018334Speter				*t++ = ',';
13118334Speter			class = t;
13218334Speter		}
13318334Speter		if (srr)
13418334Speter			s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr;
13518334Speter		if (io->on_value == IPOPT_RR)
13618334Speter			op += val;
13718334Speter		else
13818334Speter			op += io->on_siz - 3;
13918334Speter	}
14018334Speter	return len - olen;
14118334Speter}
14218334Speter
14318334Speter
14418334Speteru_32_t buildopts(cp, op, len)
14518334Speterchar *cp, *op;
14618334Speterint len;
14718334Speter{
14818334Speter	struct ipopt_names *io;
14918334Speter	u_32_t msk = 0;
15018334Speter	char *s, *t;
15118334Speter	int inc, lastop = -1;
15218334Speter
15318334Speter	for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) {
15418334Speter		if ((t = strchr(s, '=')))
15518334Speter			*t++ = '\0';
15618334Speter		for (io = ionames; io->on_name; io++) {
15718334Speter			if (strcasecmp(s, io->on_name) || (msk & io->on_bit))
15818334Speter				continue;
15918334Speter			lastop = io->on_value;
16018334Speter			if ((inc = addipopt(op, io, len, t))) {
16118334Speter				op += inc;
16218334Speter				len += inc;
16318334Speter			}
16418334Speter			msk |= io->on_bit;
16518334Speter			break;
16618334Speter		}
16718334Speter		if (!io->on_name) {
16818334Speter			fprintf(stderr, "unknown IP option name %s\n", s);
16918334Speter			return 0;
17018334Speter		}
17118334Speter	}
17218334Speter
17318334Speter	if (len & 3) {
17418334Speter		while (len & 3) {
17518334Speter			*op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP;
17618334Speter			len++;
17718334Speter		}
17818334Speter	} else {
17918334Speter		if (lastop != IPOPT_EOL) {
18018334Speter			if (lastop == IPOPT_NOP)
18118334Speter				*(op - 1) = IPOPT_EOL;
18218334Speter			else {
18318334Speter				*op++ = IPOPT_NOP;
18418334Speter				*op++ = IPOPT_NOP;
18518334Speter				*op++ = IPOPT_NOP;
18618334Speter				*op = IPOPT_EOL;
18718334Speter				len += 4;
18818334Speter			}
18918334Speter		}
19018334Speter	}
19118334Speter	return len;
19218334Speter}
19318334Speter