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