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