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