139209Sgibbs/* $FreeBSD$ */ 239209Sgibbs 339209Sgibbs/* 439209Sgibbs * Copyright (C) 2012 by Darren Reed. 539209Sgibbs * 639209Sgibbs * See the IPFILTER.LICENCE file for details on licencing. 739209Sgibbs * 839209Sgibbs */ 939209Sgibbs#if !defined(lint) 1039209Sgibbsstatic const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; 1139209Sgibbsstatic const char rcsid[] = "@(#)$Id$"; 1239209Sgibbs#endif 1339209Sgibbs#include <sys/param.h> 1439209Sgibbs#include <sys/types.h> 1539209Sgibbs#include <sys/time.h> 1639209Sgibbs#include <sys/socket.h> 1739209Sgibbs#include <netinet/in.h> 1839209Sgibbs#include <netinet/in_systm.h> 1939209Sgibbs#include <netinet/ip.h> 2039209Sgibbs#include <stdio.h> 2139209Sgibbs#include <string.h> 2239209Sgibbs#include <stdlib.h> 2339209Sgibbs#ifndef linux 2439209Sgibbs#include <netinet/ip_var.h> 2547933Smpp#endif 2639209Sgibbs#include <netinet/tcp.h> 2739209Sgibbs#include <arpa/inet.h> 2839209Sgibbs#include "ipsend.h" 2939209Sgibbs 3039209Sgibbs 3139209Sgibbs#ifndef __P 3239209Sgibbs# ifdef __STDC__ 3339209Sgibbs# define __P(x) x 3439209Sgibbs# else 3539209Sgibbs# define __P(x) () 3639209Sgibbs# endif 3739209Sgibbs#endif 3839209Sgibbs 3939209Sgibbs 4039209Sgibbsstruct ipopt_names ionames[] = { 4139209Sgibbs { IPOPT_EOL, 0x01, 1, "eol" }, 4239209Sgibbs { IPOPT_NOP, 0x02, 1, "nop" }, 4339209Sgibbs { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */ 4439209Sgibbs { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */ 4539209Sgibbs { IPOPT_SECURITY, 0x08, 11, "sec-level" }, 4639209Sgibbs { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */ 4739209Sgibbs { IPOPT_SATID, 0x20, 4, "satid" }, 4839209Sgibbs { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */ 4939209Sgibbs { 0, 0, 0, NULL } /* must be last */ 5039209Sgibbs}; 5139209Sgibbs 5239209Sgibbsstruct ipopt_names secnames[] = { 5339209Sgibbs { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" }, 5439209Sgibbs { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" }, 5539209Sgibbs { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" }, 5639209Sgibbs { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" }, 5739209Sgibbs { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" }, 5839209Sgibbs { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" }, 5939209Sgibbs { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" }, 6039209Sgibbs { 0, 0, 0, NULL } /* must be last */ 6139209Sgibbs}; 6239209Sgibbs 6339209Sgibbs 6439209Sgibbsu_short ipseclevel(slevel) 6539209Sgibbs char *slevel; 6639209Sgibbs{ 6739209Sgibbs struct ipopt_names *so; 6839209Sgibbs 6939209Sgibbs for (so = secnames; so->on_name; so++) 7039209Sgibbs if (!strcasecmp(slevel, so->on_name)) 7139209Sgibbs break; 7239209Sgibbs 7339209Sgibbs if (!so->on_name) { 7439209Sgibbs fprintf(stderr, "no such security level: %s\n", slevel); 7539209Sgibbs return 0; 7639209Sgibbs } 7739209Sgibbs return so->on_value; 7839209Sgibbs} 7939209Sgibbs 8039209Sgibbs 8139209Sgibbsint addipopt(op, io, len, class) 8239209Sgibbs char *op; 8339209Sgibbs struct ipopt_names *io; 8439209Sgibbs int len; 8539209Sgibbs char *class; 8639209Sgibbs{ 8739209Sgibbs struct in_addr ipadr; 8839209Sgibbs int olen = len, srr = 0; 8939209Sgibbs u_short val; 9039209Sgibbs u_char lvl; 9139209Sgibbs char *s = op, *t; 9239209Sgibbs 9339209Sgibbs if ((len + io->on_siz) > 48) { 9439209Sgibbs fprintf(stderr, "options too long\n"); 9539209Sgibbs return 0; 9639209Sgibbs } 9739209Sgibbs len += io->on_siz; 9839209Sgibbs *op++ = io->on_value; 9939209Sgibbs if (io->on_siz > 1) { 10039209Sgibbs /* 10139209Sgibbs * Allow option to specify RR buffer length in bytes. 10239209Sgibbs */ 10339209Sgibbs if (io->on_value == IPOPT_RR) { 10439209Sgibbs val = (class && *class) ? atoi(class) : 4; 10539209Sgibbs *op++ = val + io->on_siz; 10639209Sgibbs len += val; 10739209Sgibbs } else 10839209Sgibbs *op++ = io->on_siz; 10939209Sgibbs if (io->on_value == IPOPT_TS) 11039209Sgibbs *op++ = IPOPT_MINOFF + 1; 11139209Sgibbs else 11239209Sgibbs *op++ = IPOPT_MINOFF; 11339209Sgibbs 11439209Sgibbs while (class && *class) { 11539209Sgibbs t = NULL; 11639209Sgibbs switch (io->on_value) 11739209Sgibbs { 11839209Sgibbs case IPOPT_SECURITY : 11939209Sgibbs lvl = ipseclevel(class); 12039209Sgibbs *(op - 1) = lvl; 12139209Sgibbs break; 12239209Sgibbs case IPOPT_LSRR : 12339209Sgibbs case IPOPT_SSRR : 12439209Sgibbs if ((t = strchr(class, ','))) 12539209Sgibbs *t = '\0'; 12639209Sgibbs ipadr.s_addr = inet_addr(class); 12739209Sgibbs srr++; 12839209Sgibbs bcopy((char *)&ipadr, op, sizeof(ipadr)); 12939209Sgibbs op += sizeof(ipadr); 13039209Sgibbs break; 13139209Sgibbs case IPOPT_SATID : 13239209Sgibbs val = atoi(class); 13339209Sgibbs bcopy((char *)&val, op, 2); 13439209Sgibbs break; 13547933Smpp } 13639209Sgibbs 13739209Sgibbs if (t) 13839209Sgibbs *t++ = ','; 13939209Sgibbs class = t; 14039209Sgibbs } 14139209Sgibbs if (srr) 14239209Sgibbs s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr; 14339209Sgibbs if (io->on_value == IPOPT_RR) 14439209Sgibbs op += val; 14539209Sgibbs else 14639209Sgibbs op += io->on_siz - 3; 14739209Sgibbs } 14839209Sgibbs return len - olen; 14939209Sgibbs} 15039209Sgibbs 15139209Sgibbs 15239209Sgibbsu_32_t buildopts(cp, op, len) 15339209Sgibbs char *cp, *op; 15439209Sgibbs int len; 15539209Sgibbs{ 15639209Sgibbs struct ipopt_names *io; 15739209Sgibbs u_32_t msk = 0; 15839209Sgibbs char *s, *t; 15939209Sgibbs int inc, lastop = -1; 16039209Sgibbs 16139209Sgibbs for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { 16247933Smpp if ((t = strchr(s, '='))) 16339209Sgibbs *t++ = '\0'; 16439209Sgibbs for (io = ionames; io->on_name; io++) { 16539209Sgibbs if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) 16639209Sgibbs continue; 16739209Sgibbs lastop = io->on_value; 16839209Sgibbs if ((inc = addipopt(op, io, len, t))) { 16939209Sgibbs op += inc; 17039209Sgibbs len += inc; 17139209Sgibbs } 17239209Sgibbs msk |= io->on_bit; 17339209Sgibbs break; 17439209Sgibbs } 17547933Smpp if (!io->on_name) { 17639209Sgibbs fprintf(stderr, "unknown IP option name %s\n", s); 17739209Sgibbs return 0; 17839209Sgibbs } 17939209Sgibbs } 18039209Sgibbs 18139209Sgibbs if (len & 3) { 18239209Sgibbs while (len & 3) { 18339209Sgibbs *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP; 18439209Sgibbs len++; 18539209Sgibbs } 18639209Sgibbs } else { 18747933Smpp if (lastop != IPOPT_EOL) { 18839209Sgibbs if (lastop == IPOPT_NOP) 18939209Sgibbs *(op - 1) = IPOPT_EOL; 19039209Sgibbs else { 19139209Sgibbs *op++ = IPOPT_NOP; 19239209Sgibbs *op++ = IPOPT_NOP; 19339209Sgibbs *op++ = IPOPT_NOP; 19439209Sgibbs *op = IPOPT_EOL; 19539209Sgibbs len += 4; 19639209Sgibbs } 19739209Sgibbs } 19839209Sgibbs } 19939209Sgibbs return len; 20039209Sgibbs} 20139209Sgibbs