ipsopt.c revision 92686
1255332Scy/* 2255332Scy * Copyright (C) 1995-1998 by Darren Reed. 3254219Scy * 4254219Scy * See the IPFILTER.LICENCE file for details on licencing. 5254219Scy */ 6254219Scy#ifdef __sgi 7254219Scy# include <sys/ptimers.h> 8254219Scy#endif 9254219Scy#include <sys/param.h> 10254219Scy#include <stdio.h> 11254219Scy#include <string.h> 12254219Scy#include <stdlib.h> 13254219Scy#include <sys/types.h> 14254219Scy#include <sys/time.h> 15254219Scy#include <sys/socket.h> 16254219Scy#include <netinet/in.h> 17254219Scy#include <netinet/in_systm.h> 18254219Scy#include <netinet/ip.h> 19254219Scy#ifndef linux 20254219Scy#include <netinet/ip_var.h> 21254219Scy#endif 22254219Scy#include <netinet/tcp.h> 23254219Scy#include <arpa/inet.h> 24254219Scy#include "ipsend.h" 25254219Scy 26254219Scy#if !defined(lint) 27254219Scystatic const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; 28254219Scystatic const char rcsid[] = "@(#)$Id: ipsopt.c,v 2.1.4.3 2002/02/22 15:32:58 darrenr Exp $"; 29254219Scy#endif 30254219Scy 31254219Scy 32254219Scystruct ipopt_names ionames[] = { 33254219Scy { IPOPT_EOL, 0x01, 1, "eol" }, 34254219Scy { IPOPT_NOP, 0x02, 1, "nop" }, 35254219Scy { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */ 36254219Scy { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */ 37254219Scy { IPOPT_SECURITY, 0x08, 11, "sec-level" }, 38254219Scy { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */ 39254219Scy { IPOPT_SATID, 0x20, 4, "satid" }, 40254219Scy { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */ 41254219Scy { 0, 0, 0, NULL } /* must be last */ 42254219Scy}; 43254219Scy 44254219Scystruct ipopt_names secnames[] = { 45254219Scy { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" }, 46254219Scy { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" }, 47254219Scy { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" }, 48254219Scy { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" }, 49254219Scy { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" }, 50254219Scy { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" }, 51254219Scy { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" }, 52254219Scy { 0, 0, 0, NULL } /* must be last */ 53254219Scy}; 54254219Scy 55254219Scy 56254219Scyu_short seclevel(slevel) 57254219Scychar *slevel; 58254219Scy{ 59254219Scy struct ipopt_names *so; 60254219Scy 61254219Scy for (so = secnames; so->on_name; so++) 62254219Scy if (!strcasecmp(slevel, so->on_name)) 63254219Scy break; 64254219Scy 65254219Scy if (!so->on_name) { 66254219Scy fprintf(stderr, "no such security level: %s\n", slevel); 67254219Scy return 0; 68254219Scy } 69254219Scy return so->on_value; 70254219Scy} 71254219Scy 72254219Scy 73254219Scyint addipopt(op, io, len, class) 74254219Scychar *op; 75254219Scystruct ipopt_names *io; 76254219Scyint len; 77254219Scychar *class; 78254219Scy{ 79254219Scy struct in_addr ipadr; 80254219Scy int olen = len, srr = 0; 81254219Scy u_short val; 82254219Scy u_char lvl; 83254219Scy char *s = op, *t; 84254219Scy 85254219Scy if ((len + io->on_siz) > 48) { 86254219Scy fprintf(stderr, "options too long\n"); 87254219Scy return 0; 88254219Scy } 89254219Scy len += io->on_siz; 90254219Scy *op++ = io->on_value; 91254219Scy if (io->on_siz > 1) { 92254219Scy /* 93254219Scy * Allow option to specify RR buffer length in bytes. 94254219Scy */ 95254219Scy if (io->on_value == IPOPT_RR) { 96254219Scy val = (class && *class) ? atoi(class) : 4; 97254219Scy *op++ = val + io->on_siz; 98254219Scy len += val; 99254219Scy } else 100254219Scy *op++ = io->on_siz; 101254219Scy *op++ = IPOPT_MINOFF; 102254219Scy 103254219Scy while (class && *class) { 104254219Scy t = NULL; 105254219Scy switch (io->on_value) 106254219Scy { 107254219Scy case IPOPT_SECURITY : 108254219Scy lvl = seclevel(class); 109254219Scy *(op - 1) = lvl; 110254219Scy break; 111254219Scy case IPOPT_LSRR : 112254219Scy case IPOPT_SSRR : 113254219Scy if ((t = strchr(class, ','))) 114254219Scy *t = '\0'; 115254219Scy ipadr.s_addr = inet_addr(class); 116254219Scy srr++; 117254219Scy bcopy((char *)&ipadr, op, sizeof(ipadr)); 118254219Scy op += sizeof(ipadr); 119254219Scy break; 120254219Scy case IPOPT_SATID : 121254219Scy val = atoi(class); 122254219Scy bcopy((char *)&val, op, 2); 123254219Scy break; 124254219Scy } 125254219Scy 126254219Scy if (t) 127254219Scy *t++ = ','; 128254219Scy class = t; 129254219Scy } 130254219Scy if (srr) 131 s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr; 132 if (io->on_value == IPOPT_RR) 133 op += val; 134 else 135 op += io->on_siz - 3; 136 } 137 return len - olen; 138} 139 140 141u_32_t buildopts(cp, op, len) 142char *cp, *op; 143int len; 144{ 145 struct ipopt_names *io; 146 u_32_t msk = 0; 147 char *s, *t; 148 int inc, lastop = -1; 149 150 for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { 151 if ((t = strchr(s, '='))) 152 *t++ = '\0'; 153 for (io = ionames; io->on_name; io++) { 154 if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) 155 continue; 156 lastop = io->on_value; 157 if ((inc = addipopt(op, io, len, t))) { 158 op += inc; 159 len += inc; 160 } 161 msk |= io->on_bit; 162 break; 163 } 164 if (!io->on_name) { 165 fprintf(stderr, "unknown IP option name %s\n", s); 166 return 0; 167 } 168 } 169 170 if (len & 3) { 171 while (len & 3) { 172 *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP; 173 len++; 174 } 175 } else { 176 if (lastop != IPOPT_EOL) { 177 if (lastop == IPOPT_NOP) 178 *(op - 1) = IPOPT_EOL; 179 else { 180 *op++ = IPOPT_NOP; 181 *op++ = IPOPT_NOP; 182 *op++ = IPOPT_NOP; 183 *op = IPOPT_EOL; 184 len += 4; 185 } 186 } 187 } 188 return len; 189} 190