ipsopt.c revision 145519
1145519Sdarrenr/* $FreeBSD: head/contrib/ipfilter/ipsend/ipsopt.c 145519 2005-04-25 18:20:15Z darrenr $ */ 2145510Sdarrenr 322514Sdarrenr/* 453024Sguido * Copyright (C) 1995-1998 by Darren Reed. 522514Sdarrenr * 680486Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr * 822514Sdarrenr */ 9145510Sdarrenr#if !defined(lint) 10145510Sdarrenrstatic const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; 11145510Sdarrenrstatic const char rcsid[] = "@(#)Id: ipsopt.c,v 2.4.4.1 2004/03/23 12:58:05 darrenr Exp"; 1292686Sdarrenr#endif 1392686Sdarrenr#include <sys/param.h> 1422514Sdarrenr#include <sys/types.h> 1522514Sdarrenr#include <sys/time.h> 1622514Sdarrenr#include <sys/socket.h> 1722514Sdarrenr#include <netinet/in.h> 1822514Sdarrenr#include <netinet/in_systm.h> 1922514Sdarrenr#include <netinet/ip.h> 20145510Sdarrenr#include <stdio.h> 21145510Sdarrenr#include <string.h> 22145510Sdarrenr#include <stdlib.h> 2331183Speter#ifndef linux 2431183Speter#include <netinet/ip_var.h> 2531183Speter#endif 2631183Speter#include <netinet/tcp.h> 2731183Speter#include <arpa/inet.h> 2831183Speter#include "ipsend.h" 2922514Sdarrenr 30145510Sdarrenr 31145510Sdarrenr#ifndef __P 32145510Sdarrenr# ifdef __STDC__ 33145510Sdarrenr# define __P(x) x 34145510Sdarrenr# else 35145510Sdarrenr# define __P(x) () 36145510Sdarrenr# endif 3724583Sdarrenr#endif 3824583Sdarrenr 3924583Sdarrenr 4022514Sdarrenrstruct ipopt_names ionames[] = { 4122514Sdarrenr { IPOPT_EOL, 0x01, 1, "eol" }, 4222514Sdarrenr { IPOPT_NOP, 0x02, 1, "nop" }, 4331183Speter { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */ 4422514Sdarrenr { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */ 4522514Sdarrenr { IPOPT_SECURITY, 0x08, 11, "sec-level" }, 4622514Sdarrenr { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */ 4722514Sdarrenr { IPOPT_SATID, 0x20, 4, "satid" }, 4822514Sdarrenr { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */ 4922514Sdarrenr { 0, 0, 0, NULL } /* must be last */ 5022514Sdarrenr}; 5122514Sdarrenr 5222514Sdarrenrstruct ipopt_names secnames[] = { 5322514Sdarrenr { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" }, 5422514Sdarrenr { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" }, 5522514Sdarrenr { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" }, 5622514Sdarrenr { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" }, 5722514Sdarrenr { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" }, 5822514Sdarrenr { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" }, 5922514Sdarrenr { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" }, 6022514Sdarrenr { 0, 0, 0, NULL } /* must be last */ 6122514Sdarrenr}; 6222514Sdarrenr 6322514Sdarrenr 64145510Sdarrenru_short ipseclevel(slevel) 6522514Sdarrenrchar *slevel; 6622514Sdarrenr{ 6722514Sdarrenr struct ipopt_names *so; 6822514Sdarrenr 6922514Sdarrenr for (so = secnames; so->on_name; so++) 7022514Sdarrenr if (!strcasecmp(slevel, so->on_name)) 7122514Sdarrenr break; 7222514Sdarrenr 7322514Sdarrenr if (!so->on_name) { 7422514Sdarrenr fprintf(stderr, "no such security level: %s\n", slevel); 7522514Sdarrenr return 0; 7622514Sdarrenr } 7722514Sdarrenr return so->on_value; 7822514Sdarrenr} 7922514Sdarrenr 8022514Sdarrenr 8131183Speterint addipopt(op, io, len, class) 8231183Speterchar *op; 8331183Speterstruct ipopt_names *io; 8431183Speterint len; 8531183Speterchar *class; 8631183Speter{ 8731183Speter struct in_addr ipadr; 8831183Speter int olen = len, srr = 0; 8931183Speter u_short val; 9031183Speter u_char lvl; 9131183Speter char *s = op, *t; 9231183Speter 9331183Speter if ((len + io->on_siz) > 48) { 9431183Speter fprintf(stderr, "options too long\n"); 9531183Speter return 0; 9631183Speter } 9731183Speter len += io->on_siz; 9831183Speter *op++ = io->on_value; 9931183Speter if (io->on_siz > 1) { 10031183Speter /* 10131183Speter * Allow option to specify RR buffer length in bytes. 10231183Speter */ 10331183Speter if (io->on_value == IPOPT_RR) { 10431183Speter val = (class && *class) ? atoi(class) : 4; 10531183Speter *op++ = val + io->on_siz; 10631183Speter len += val; 10731183Speter } else 10831183Speter *op++ = io->on_siz; 109130887Sdarrenr if (io->on_value == IPOPT_TS) 110130887Sdarrenr *op++ = IPOPT_MINOFF + 1; 111130887Sdarrenr else 112130887Sdarrenr *op++ = IPOPT_MINOFF; 11331183Speter 11431183Speter while (class && *class) { 11531183Speter t = NULL; 11631183Speter switch (io->on_value) 11731183Speter { 11831183Speter case IPOPT_SECURITY : 119145510Sdarrenr lvl = ipseclevel(class); 12031183Speter *(op - 1) = lvl; 12131183Speter break; 12231183Speter case IPOPT_LSRR : 12331183Speter case IPOPT_SSRR : 12431183Speter if ((t = strchr(class, ','))) 12531183Speter *t = '\0'; 12631183Speter ipadr.s_addr = inet_addr(class); 12731183Speter srr++; 12831183Speter bcopy((char *)&ipadr, op, sizeof(ipadr)); 12931183Speter op += sizeof(ipadr); 13031183Speter break; 13131183Speter case IPOPT_SATID : 13231183Speter val = atoi(class); 13331183Speter bcopy((char *)&val, op, 2); 13431183Speter break; 13531183Speter } 13631183Speter 13731183Speter if (t) 13831183Speter *t++ = ','; 13931183Speter class = t; 14031183Speter } 14131183Speter if (srr) 14231183Speter s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr; 14331183Speter if (io->on_value == IPOPT_RR) 14431183Speter op += val; 14531183Speter else 14631183Speter op += io->on_siz - 3; 14731183Speter } 14831183Speter return len - olen; 14931183Speter} 15031183Speter 15131183Speter 15231183Speteru_32_t buildopts(cp, op, len) 15322514Sdarrenrchar *cp, *op; 15431183Speterint len; 15522514Sdarrenr{ 15622514Sdarrenr struct ipopt_names *io; 15731183Speter u_32_t msk = 0; 15822514Sdarrenr char *s, *t; 15931183Speter int inc, lastop = -1; 16022514Sdarrenr 16122514Sdarrenr for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { 16222514Sdarrenr if ((t = strchr(s, '='))) 16322514Sdarrenr *t++ = '\0'; 16422514Sdarrenr for (io = ionames; io->on_name; io++) { 16522514Sdarrenr if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) 16622514Sdarrenr continue; 16731183Speter lastop = io->on_value; 16831183Speter if ((inc = addipopt(op, io, len, t))) { 16931183Speter op += inc; 17031183Speter len += inc; 17122514Sdarrenr } 17222514Sdarrenr msk |= io->on_bit; 17322514Sdarrenr break; 17422514Sdarrenr } 17522514Sdarrenr if (!io->on_name) { 17622514Sdarrenr fprintf(stderr, "unknown IP option name %s\n", s); 17722514Sdarrenr return 0; 17822514Sdarrenr } 17922514Sdarrenr } 18031183Speter 18131183Speter if (len & 3) { 18231183Speter while (len & 3) { 18331183Speter *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP; 18431183Speter len++; 18531183Speter } 18631183Speter } else { 18731183Speter if (lastop != IPOPT_EOL) { 18831183Speter if (lastop == IPOPT_NOP) 18931183Speter *(op - 1) = IPOPT_EOL; 19031183Speter else { 19131183Speter *op++ = IPOPT_NOP; 19231183Speter *op++ = IPOPT_NOP; 19331183Speter *op++ = IPOPT_NOP; 19431183Speter *op = IPOPT_EOL; 19531183Speter len += 4; 19631183Speter } 19731183Speter } 19831183Speter } 19922514Sdarrenr return len; 20022514Sdarrenr} 201