ipsopt.c revision 80486
122514Sdarrenr/* 253024Sguido * Copyright (C) 1995-1998 by Darren Reed. 322514Sdarrenr * 480486Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 522514Sdarrenr */ 622514Sdarrenr#include <stdio.h> 722514Sdarrenr#include <string.h> 831183Speter#include <stdlib.h> 922514Sdarrenr#include <sys/types.h> 1022514Sdarrenr#include <sys/time.h> 1122514Sdarrenr#include <sys/socket.h> 1222514Sdarrenr#include <netinet/in.h> 1322514Sdarrenr#include <netinet/in_systm.h> 1422514Sdarrenr#include <netinet/ip.h> 1531183Speter#ifndef linux 1631183Speter#include <netinet/ip_var.h> 1731183Speter#endif 1831183Speter#include <netinet/tcp.h> 1931183Speter#include <arpa/inet.h> 2031183Speter#include "ipsend.h" 2122514Sdarrenr 2280486Sdarrenr#if !defined(lint) 2380486Sdarrenrstatic const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; 2480486Sdarrenrstatic const char rcsid[] = "@(#)$Id: ipsopt.c,v 2.1.4.2 2001/07/15 22:00:14 darrenr Exp $"; 2524583Sdarrenr#endif 2624583Sdarrenr 2724583Sdarrenr 2822514Sdarrenrstruct ipopt_names ionames[] = { 2922514Sdarrenr { IPOPT_EOL, 0x01, 1, "eol" }, 3022514Sdarrenr { IPOPT_NOP, 0x02, 1, "nop" }, 3131183Speter { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */ 3222514Sdarrenr { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */ 3322514Sdarrenr { IPOPT_SECURITY, 0x08, 11, "sec-level" }, 3422514Sdarrenr { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */ 3522514Sdarrenr { IPOPT_SATID, 0x20, 4, "satid" }, 3622514Sdarrenr { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */ 3722514Sdarrenr { 0, 0, 0, NULL } /* must be last */ 3822514Sdarrenr}; 3922514Sdarrenr 4022514Sdarrenrstruct ipopt_names secnames[] = { 4122514Sdarrenr { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" }, 4222514Sdarrenr { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" }, 4322514Sdarrenr { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" }, 4422514Sdarrenr { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" }, 4522514Sdarrenr { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" }, 4622514Sdarrenr { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" }, 4722514Sdarrenr { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" }, 4822514Sdarrenr { 0, 0, 0, NULL } /* must be last */ 4922514Sdarrenr}; 5022514Sdarrenr 5122514Sdarrenr 5222514Sdarrenru_short seclevel(slevel) 5322514Sdarrenrchar *slevel; 5422514Sdarrenr{ 5522514Sdarrenr struct ipopt_names *so; 5622514Sdarrenr 5722514Sdarrenr for (so = secnames; so->on_name; so++) 5822514Sdarrenr if (!strcasecmp(slevel, so->on_name)) 5922514Sdarrenr break; 6022514Sdarrenr 6122514Sdarrenr if (!so->on_name) { 6222514Sdarrenr fprintf(stderr, "no such security level: %s\n", slevel); 6322514Sdarrenr return 0; 6422514Sdarrenr } 6522514Sdarrenr return so->on_value; 6622514Sdarrenr} 6722514Sdarrenr 6822514Sdarrenr 6931183Speterint addipopt(op, io, len, class) 7031183Speterchar *op; 7131183Speterstruct ipopt_names *io; 7231183Speterint len; 7331183Speterchar *class; 7431183Speter{ 7531183Speter struct in_addr ipadr; 7631183Speter int olen = len, srr = 0; 7731183Speter u_short val; 7831183Speter u_char lvl; 7931183Speter char *s = op, *t; 8031183Speter 8131183Speter if ((len + io->on_siz) > 48) { 8231183Speter fprintf(stderr, "options too long\n"); 8331183Speter return 0; 8431183Speter } 8531183Speter len += io->on_siz; 8631183Speter *op++ = io->on_value; 8731183Speter if (io->on_siz > 1) { 8831183Speter /* 8931183Speter * Allow option to specify RR buffer length in bytes. 9031183Speter */ 9131183Speter if (io->on_value == IPOPT_RR) { 9231183Speter val = (class && *class) ? atoi(class) : 4; 9331183Speter *op++ = val + io->on_siz; 9431183Speter len += val; 9531183Speter } else 9631183Speter *op++ = io->on_siz; 9731183Speter *op++ = IPOPT_MINOFF; 9831183Speter 9931183Speter while (class && *class) { 10031183Speter t = NULL; 10131183Speter switch (io->on_value) 10231183Speter { 10331183Speter case IPOPT_SECURITY : 10431183Speter lvl = seclevel(class); 10531183Speter *(op - 1) = lvl; 10631183Speter break; 10731183Speter case IPOPT_LSRR : 10831183Speter case IPOPT_SSRR : 10931183Speter if ((t = strchr(class, ','))) 11031183Speter *t = '\0'; 11131183Speter ipadr.s_addr = inet_addr(class); 11231183Speter srr++; 11331183Speter bcopy((char *)&ipadr, op, sizeof(ipadr)); 11431183Speter op += sizeof(ipadr); 11531183Speter break; 11631183Speter case IPOPT_SATID : 11731183Speter val = atoi(class); 11831183Speter bcopy((char *)&val, op, 2); 11931183Speter break; 12031183Speter } 12131183Speter 12231183Speter if (t) 12331183Speter *t++ = ','; 12431183Speter class = t; 12531183Speter } 12631183Speter if (srr) 12731183Speter s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr; 12831183Speter if (io->on_value == IPOPT_RR) 12931183Speter op += val; 13031183Speter else 13131183Speter op += io->on_siz - 3; 13231183Speter } 13331183Speter return len - olen; 13431183Speter} 13531183Speter 13631183Speter 13731183Speteru_32_t buildopts(cp, op, len) 13822514Sdarrenrchar *cp, *op; 13931183Speterint len; 14022514Sdarrenr{ 14122514Sdarrenr struct ipopt_names *io; 14231183Speter u_32_t msk = 0; 14322514Sdarrenr char *s, *t; 14431183Speter int inc, lastop = -1; 14522514Sdarrenr 14622514Sdarrenr for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { 14722514Sdarrenr if ((t = strchr(s, '='))) 14822514Sdarrenr *t++ = '\0'; 14922514Sdarrenr for (io = ionames; io->on_name; io++) { 15022514Sdarrenr if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) 15122514Sdarrenr continue; 15231183Speter lastop = io->on_value; 15331183Speter if ((inc = addipopt(op, io, len, t))) { 15431183Speter op += inc; 15531183Speter len += inc; 15622514Sdarrenr } 15722514Sdarrenr msk |= io->on_bit; 15822514Sdarrenr break; 15922514Sdarrenr } 16022514Sdarrenr if (!io->on_name) { 16122514Sdarrenr fprintf(stderr, "unknown IP option name %s\n", s); 16222514Sdarrenr return 0; 16322514Sdarrenr } 16422514Sdarrenr } 16531183Speter 16631183Speter if (len & 3) { 16731183Speter while (len & 3) { 16831183Speter *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP; 16931183Speter len++; 17031183Speter } 17131183Speter } else { 17231183Speter if (lastop != IPOPT_EOL) { 17331183Speter if (lastop == IPOPT_NOP) 17431183Speter *(op - 1) = IPOPT_EOL; 17531183Speter else { 17631183Speter *op++ = IPOPT_NOP; 17731183Speter *op++ = IPOPT_NOP; 17831183Speter *op++ = IPOPT_NOP; 17931183Speter *op = IPOPT_EOL; 18031183Speter len += 4; 18131183Speter } 18231183Speter } 18331183Speter } 18422514Sdarrenr return len; 18522514Sdarrenr} 186