add TFT(Packet Filter) in Create Bearer Request

This commit is contained in:
Sukchan Lee 2017-09-06 15:02:43 +09:00
parent d1056a06c8
commit 886ef5a747
29 changed files with 13325 additions and 48 deletions

View File

@ -28,6 +28,7 @@ case $host in
*linux*)
OSDIR="unix"
OSCPPFLAGS="-DLINUX=1"
IPFW_CPPFLAGS="-DNEED_SYSCTLBYNAME -DNEED_SIN_LEN"
;;
*-apple-darwin*)
OSDIR="unix"
@ -39,6 +40,7 @@ case $host in
esac
AC_SUBST(OSCPPFLAGS)
AC_SUBST(OSDIR)
AC_SUBST(IPFW_CPPFLAGS)
AH_TOP([
#ifndef __NEXTEPC_CONFIG_H__
@ -329,6 +331,7 @@ AC_CONFIG_FILES([lib/fd/gx/Makefile])
AC_CONFIG_FILES([lib/fd/s6a/Makefile])
AC_CONFIG_FILES([lib/fd/Makefile])
AC_CONFIG_FILES([lib/gtp/Makefile])
AC_CONFIG_FILES([lib/ipfw/Makefile])
AC_CONFIG_FILES([lib/Makefile])
AC_CONFIG_FILES([src/mme/Makefile])
AC_CONFIG_FILES([src/hss/Makefile])

View File

@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = core logger base s1ap nas fd gtp
SUBDIRS = core logger base s1ap nas fd gtp ipfw
MAINTAINERCLEANFILES = Makefile.in
MOSTLYCLEANFILES = *.stackdump

View File

@ -11,14 +11,17 @@ extern "C" {
#define MAX_NUM_OF_UE 128
#define MAX_NUM_OF_SESS 4
#define MAX_NUM_OF_BEARER 4
#define MAX_NUM_OF_PF 16 /* Num of Packet Filter per Bearer */
#define MAX_NUM_OF_GTP_NODE 8
#define MAX_POOL_OF_UE (MAX_NUM_OF_ENB * MAX_NUM_OF_UE)
#define MAX_POOL_OF_SESS (MAX_POOL_OF_UE * MAX_NUM_OF_SESS)
#define MAX_POOL_OF_BEARER (MAX_POOL_OF_SESS * MAX_NUM_OF_BEARER)
#define MAX_POOL_OF_PF (MAX_POOL_OF_BEARER * MAX_NUM_OF_PF)
#define MAX_NUM_OF_PCC_RULE 8
#define MAX_NUM_OF_FLOW 8
#define MAX_NUM_OF_PCC_RULE 8
#define MAX_NUM_OF_FLOW 8 /* Num of Flow per PCC Rule */
#define MAX_NUM_OF_PACKET_FILTER 16 /* Num of Packet Filter per Bearer */
#define MAX_SDU_LEN 2048
#define IPV6_LEN 16
@ -147,6 +150,8 @@ typedef struct _qos_t {
/**********************************
* Flow Structure */
#define FLOW_DOWNLINK_ONLY 1
#define FLOW_UPLINK_ONLY 2
typedef struct _flow_t {
c_uint8_t direction;
c_int8_t *description;

View File

@ -97,6 +97,143 @@ c_int16_t gtp_build_bearer_qos(
return octet->len;
}
/* 8.19 EPS Bearer Level Traffic Flow Template (Bearer TFT)
* See subclause 10.5.6.12 in 3GPP TS 24.008 [13]. */
c_int16_t gtp_build_tft(
tlv_octet_t *octet, gtp_tft_t *tft, void *data, int data_len)
{
gtp_tft_t target;
c_uint16_t size = 0;
int i, j;
d_assert(tft, return -1, "Null param");
d_assert(octet, return -1, "Null param");
d_assert(data, return -1, "Null param");
d_assert(data_len >= GTP_MAX_TRAFFIC_FLOW_TEMPLATE,
return -1, "Null param");
octet->data = data;
memcpy(&target, tft, sizeof(gtp_tft_t));
d_assert(size + sizeof(target.flags) <= data_len,
return -1, "encode error");
memcpy(octet->data + size, &target.flags, sizeof(target.flags));
size += sizeof(target.flags);
for (i = 0; i < target.num_of_packet_filter; i++)
{
d_assert(size + sizeof(target.pf[i].flags) <= data_len,
return -1, "encode error");
memcpy(octet->data + size, &target.pf[i].flags,
sizeof(target.pf[i].flags));
size += sizeof(target.pf[i].flags);
d_assert(size + sizeof(target.pf[i].precedence) <= data_len,
return -1, "encode error");
memcpy(octet->data + size, &target.pf[i].precedence,
sizeof(target.pf[i].precedence));
size += sizeof(target.pf[i].precedence);
d_assert(size + sizeof(target.pf[i].length) <= data_len,
return -1, "encode error");
memcpy(octet->data + size, &target.pf[i].length,
sizeof(target.pf[i].length));
size += sizeof(target.pf[i].length);
for (j = 0; j < target.pf[i].num_of_component; j++)
{
d_assert(size +
sizeof(target.pf[i].component[j].type) <= data_len,
return -1, "encode error");
memcpy(octet->data + size, &target.pf[i].component[j].type,
sizeof(target.pf[i].component[j].type));
size += sizeof(target.pf[i].component[j].type);
switch(target.pf[i].component[j].type)
{
case GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE:
{
d_assert(size +
sizeof(target.pf[i].component[j].proto) <= data_len,
return -1, "encode error");
memcpy(octet->data + size, &target.pf[i].component[j].proto,
sizeof(target.pf[i].component[j].proto));
size += sizeof(target.pf[i].component[j].proto);
break;
}
case GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE:
case GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE:
d_assert(size +
sizeof(target.pf[i].component[j].ipv4.addr)
<= data_len,
return -1, "encode error");
memcpy(octet->data + size,
&target.pf[i].component[j].ipv4.addr,
sizeof(target.pf[i].component[j].ipv4.addr));
size += sizeof(target.pf[i].component[j].ipv4.addr);
d_assert(size +
sizeof(target.pf[i].component[j].ipv4.mask)
<= data_len,
return -1, "encode error");
memcpy(octet->data + size,
&target.pf[i].component[j].ipv4.mask,
sizeof(target.pf[i].component[j].ipv4.mask));
size += sizeof(target.pf[i].component[j].ipv4.mask);
break;
case GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE:
case GTP_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE:
d_assert(size +
sizeof(target.pf[i].component[j].port.low)
<= data_len,
return -1, "encode error");
target.pf[i].component[j].port.low =
htons(target.pf[i].component[j].port.low);
memcpy(octet->data + size,
&target.pf[i].component[j].port.low,
sizeof(target.pf[i].component[j].port.low));
size += sizeof(target.pf[i].component[j].port.low);
break;
case GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE:
case GTP_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE:
d_assert(size +
sizeof(target.pf[i].component[j].port.low)
<= data_len,
return -1, "encode error");
target.pf[i].component[j].port.low =
htons(target.pf[i].component[j].port.low);
memcpy(octet->data + size,
&target.pf[i].component[j].port.low,
sizeof(target.pf[i].component[j].port.low));
size += sizeof(target.pf[i].component[j].port.low);
d_assert(size +
sizeof(target.pf[i].component[j].port.high)
<= data_len,
return -1, "encode error");
target.pf[i].component[j].port.high =
htons(target.pf[i].component[j].port.high);
memcpy(octet->data + size,
&target.pf[i].component[j].port.high,
sizeof(target.pf[i].component[j].port.high));
size += sizeof(target.pf[i].component[j].port.high);
break;
default:
d_error("Unknown Packet Filter Type(%d)",
target.pf[i].component[j].type);
return -1;
}
}
}
octet->len = size;
return octet->len;
}
/* 8.21 User Location Information (ULI) */
c_int16_t gtp_parse_uli(gtp_uli_t *uli, tlv_octet_t *octet)
{

View File

@ -185,6 +185,72 @@ CORE_DECLARE(c_int16_t) gtp_build_bearer_qos(
#define GTP_RAT_TYPE_VIRTUAL 7
#define GTP_RAT_TYPE_EUTRAN_NB_IOT 8
/* 8.19 EPS Bearer Level Traffic Flow Template (Bearer TFT)
* See subclause 10.5.6.12 in 3GPP TS 24.008 [13]. */
#define GTP_MAX_TRAFFIC_FLOW_TEMPLATE 255
#define GTP_MAX_NUM_OF_PACKET_FILTER_COMPONENT 16
typedef struct _gtp_tft_t {
union {
struct {
#define GTP_TFT_CODE_IGNORE_THIS_IE 0
#define GTP_TFT_CODE_CREATE_NEW_TFT 1
#define GTP_TFT_CODE_DELETE_EXISTING_TFT 2
#define GTP_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT 3
#define GTP_TFT_CODE_REPLACE_PACKET_FILTERS_IN_EXISTING 4
#define GTP_TFT_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING 5
#define GTP_TFT_CODE_NO_TFT_OPERATION 6
ED3(c_uint8_t code:3;,
c_uint8_t e_bit:1;,
c_uint8_t num_of_packet_filter:4;)
};
c_uint8_t flags;
};
struct {
union {
struct {
ED3(c_uint8_t spare:2;,
c_uint8_t direction:2;,
c_uint8_t identifier:4;)
};
c_uint8_t flags;
};
c_uint8_t precedence;
c_uint8_t length;
#define GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE 48
#define GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE 16
#define GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE 17
#define GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE 32
#define GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE 33
#define GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE 35
#define GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE 64
#define GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE 65
#define GTP_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE 80
#define GTP_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE 81
#define GTP_PACKET_FILTER_SECURITY_PARAMETER_INDEX_TYPE 96
#define GTP_PACKET_FILTER_TOS_TRAFFIC_CLASS_TYPE 112
#define GTP_PACKET_FILTER_FLOW_LABEL_TYPE 128
struct {
c_uint8_t type;
union {
c_uint8_t proto;
struct {
c_uint32_t addr;
c_uint32_t mask;
} ipv4;
struct {
c_uint16_t low;
c_uint16_t high;
} port;
};
} component[GTP_MAX_NUM_OF_PACKET_FILTER_COMPONENT];
c_uint8_t num_of_component;
} pf[MAX_NUM_OF_PACKET_FILTER];
} gtp_tft_t;
CORE_DECLARE(c_int16_t) gtp_build_tft(
tlv_octet_t *octet, gtp_tft_t *tft, void *data, int data_len);
/* 8.21 User Location Information (ULI) */
#define GTP_MAX_ULI_LEN sizeof(gtp_uli_t)
typedef struct _gtp_uli_cgi_t {

22
lib/ipfw/Makefile.am Normal file
View File

@ -0,0 +1,22 @@
## Process this file with automake to produce Makefile.in.
noinst_LTLIBRARIES = libipfw.la
libipfw_la_SOURCES = \
ipfw2.h \
ipfw2.c dummynet.c ipv6.c tables.c \
expand_number.c humanize_number.c \
glue.c
AM_CPPFLAGS = \
-I$(top_srcdir)/lib/ipfw/objs/include_e \
-include glue.h \
-DUSERSPACE -D__BSD_VISIBLE -DNEED_STRTONUM -DNEED_ROUNDUP2 \
@IPFW_CPPFLAGS@
AM_CFLAGS = \
-Wall -Werror -Wno-shift-negative-value \
-Wno-unused-but-set-variable -Wno-unknown-warning-option
MAINTAINERCLEANFILES = Makefile.in
MOSTLYCLEANFILES = core *.stackdump

1410
lib/ipfw/dummynet.c Normal file

File diff suppressed because it is too large Load Diff

101
lib/ipfw/expand_number.c Normal file
View File

@ -0,0 +1,101 @@
/*-
* Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org>
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: head/lib/libutil/expand_number.c 211343 2010-08-15 18:32:06Z des $");
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
//#include <libutil.h>
#include <stdint.h>
/*
* Convert an expression of the following forms to a uint64_t.
* 1) A positive decimal number.
* 2) A positive decimal number followed by a 'b' or 'B' (mult by 1).
* 3) A positive decimal number followed by a 'k' or 'K' (mult by 1 << 10).
* 4) A positive decimal number followed by a 'm' or 'M' (mult by 1 << 20).
* 5) A positive decimal number followed by a 'g' or 'G' (mult by 1 << 30).
* 6) A positive decimal number followed by a 't' or 'T' (mult by 1 << 40).
* 7) A positive decimal number followed by a 'p' or 'P' (mult by 1 << 50).
* 8) A positive decimal number followed by a 'e' or 'E' (mult by 1 << 60).
*/
int
expand_number(const char *buf, uint64_t *num)
{
uint64_t number;
unsigned shift;
char *endptr;
number = strtoumax(buf, &endptr, 0);
if (endptr == buf) {
/* No valid digits. */
errno = EINVAL;
return (-1);
}
switch (tolower((unsigned char)*endptr)) {
case 'e':
shift = 60;
break;
case 'p':
shift = 50;
break;
case 't':
shift = 40;
break;
case 'g':
shift = 30;
break;
case 'm':
shift = 20;
break;
case 'k':
shift = 10;
break;
case 'b':
case '\0': /* No unit. */
*num = number;
return (0);
default:
/* Unrecognized unit. */
errno = EINVAL;
return (-1);
}
if ((number << shift) >> shift != number) {
/* Overflow */
errno = ERANGE;
return (-1);
}
*num = number << shift;
return (0);
}

555
lib/ipfw/glue.c Normal file
View File

@ -0,0 +1,555 @@
/*
* Userland functions missing in linux
* taken from /usr/src/lib/libc/stdtime/time32.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in */
#include <netinet/tcp.h> /* TCP_NODELAY */
#include <sys/uio.h>
#include <unistd.h> /* uint* types */
#include <errno.h>
#include <string.h> /* bzero */
#include <arpa/inet.h> /* htonl */
#ifndef HAVE_NAT
/* dummy nat functions */
void
ipfw_show_nat(int ac, char **av)
{
D("unsupported");
}
void
ipfw_config_nat(int ac, char **av)
{
D("unsupported");
}
#endif /* HAVE_NAT */
#ifdef NEED_STRTONUM
/* missing in linux and windows */
long long int
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr)
{
long long ret;
int errno_c = errno; /* save actual errno */
errno = 0;
#ifdef TCC
ret = strtol(nptr, (char **)errstr, 0);
#else
ret = strtoll(nptr, (char **)errstr, 0);
#endif
/* We accept only a string that represent exactly a number (ie. start
* and end with a digit).
* FreeBSD version wants errstr==NULL if no error occurs, otherwise
* errstr should point to an error string.
* For our purspose, we implement only the invalid error, ranges
* error aren't checked
*/
if (errno != 0 || nptr == *errstr || **errstr != '\0')
*errstr = "invalid";
else {
*errstr = NULL;
errno = errno_c;
}
return ret;
}
int
ishexnumber(int c)
{
return ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F') );
}
#endif /* NEED_STRTONUM */
#ifdef __linux__
int optreset; /* missing in linux */
/*
* not implemented in linux.
* taken from /usr/src/lib/libc/string/strlcpy.c
*/
size_t
strlcpy(dst, src, siz)
char *dst;
const char *src;
size_t siz;
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif /* __linux__ */
#if defined (EMULATE_SYSCTL)
//XXX missing prerequisites
#include <net/if.h> //openwrt
#include <netinet/ip.h> //openwrt
#include <netinet/ip_fw.h>
#include <netinet/ip_dummynet.h>
int do_cmd(int optname, void *optval, uintptr_t optlen);
#endif /* EMULATE_SYSCTL */
/*
* set or get system information
* XXX lock acquisition/serialize calls
*
* we export this as sys/module/ipfw_mod/parameters/___
* This function get or/and set the value of the sysctl passed by
* the name parameter. If the old value is not desired,
* oldp and oldlenp should be set to NULL.
*
* XXX
* I do not know how this works in FreeBSD in the case
* where there are no write permission on the sysctl var.
* We read the value and set return variables in any way
* but returns -1 on write failures, regardless the
* read success.
*
* Since there is no information on types, in the following
* code we assume a length of 4 is a int.
*
* Returns 0 on success, -1 on errors.
*/
int
sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t newlen)
{
#if defined (EMULATE_SYSCTL)
/*
* we embed the sysctl request in the usual sockopt mechanics.
* the sockopt buffer il filled with a dn_id with IP_DUMMYNET3
* command, and the special DN_SYSCTL_GET and DN_SYSCTL_SET
* subcommands.
* the syntax of this function is fully compatible with
* POSIX sysctlby name:
* if newp and newlen are != 0 => this is a set
* else if oldp and oldlen are != 0 => this is a get
* to avoid too much overhead in the module, the whole
* sysctltable is returned, and the parsing is done in userland,
* a probe request is done to retrieve the size needed to
* transfer the table, before the real request
* if both old and new params = 0 => this is a print
* this is a special request, done only by main()
* to implement the extension './ipfw sysctl',
* a command that bypasses the normal getopt, and that
* is available on those platforms that use this
* sysctl emulation.
* in this case, a negative oldlen signals that *oldp
* is actually a FILE* to print somewhere else than stdout
*/
int l;
int ret;
struct dn_id* oid;
struct sysctlhead* entry;
char* pstring;
char* pdata;
FILE* fp;
if((oldlenp != NULL) && ((int)*oldlenp < 0))
fp = (FILE*)oldp;
else
fp = stdout;
if(newp != NULL && newlen != 0)
{
//this is a set
l = sizeof(struct dn_id) + sizeof(struct sysctlhead) + strlen(name)+1 + newlen;
oid = malloc(l);
if (oid == NULL)
return -1;
oid->len = l;
oid->type = DN_SYSCTL_SET;
oid->id = DN_API_VERSION;
entry = (struct sysctlhead*)(oid+1);
pdata = (char*)(entry+1);
pstring = pdata + newlen;
entry->blocklen = ((sizeof(struct sysctlhead) + strlen(name)+1 + newlen) + 3) & ~3;
entry->namelen = strlen(name)+1;
entry->flags = 0;
entry->datalen = newlen;
bcopy(newp, pdata, newlen);
bcopy(name, pstring, strlen(name)+1);
ret = do_cmd(IP_DUMMYNET3, oid, (uintptr_t)l);
if (ret != 0)
return -1;
}
else
{
//this is a get or a print
l = sizeof(struct dn_id);
oid = malloc(l);
if (oid == NULL)
return -1;
oid->len = l;
oid->type = DN_SYSCTL_GET;
oid->id = DN_API_VERSION;
ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);
if (ret != 0)
return -1;
l=oid->id;
free(oid);
oid = malloc(l);
if (oid == NULL)
return -1;
oid->len = l;
oid->type = DN_SYSCTL_GET;
oid->id = DN_API_VERSION;
ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);
if (ret != 0)
return -1;
entry = (struct sysctlhead*)(oid+1);
while(entry->blocklen != 0)
{
pdata = (char*)(entry+1);
pstring = pdata+entry->datalen;
//time to check if this is a get or a print
if(name != NULL && oldp != NULL && *oldlenp > 0)
{
//this is a get
if(strcmp(name,pstring) == 0)
{
//match found, sanity chech on len
if(*oldlenp < entry->datalen)
{
printf("%s error: buffer too small\n",__FUNCTION__);
return -1;
}
*oldlenp = entry->datalen;
bcopy(pdata, oldp, *oldlenp);
return 0;
}
}
else
{
//this is a print
if( name == NULL )
goto print;
if ( (strncmp(pstring,name,strlen(name)) == 0) && ( pstring[strlen(name)]=='\0' || pstring[strlen(name)]=='.' ) )
goto print;
else
goto skip;
print:
fprintf(fp, "%s: ",pstring);
switch( entry->flags >> 2 )
{
case SYSCTLTYPE_LONG:
fprintf(fp, "%li ", *(long*)(pdata));
break;
case SYSCTLTYPE_UINT:
fprintf(fp, "%u ", *(unsigned int*)(pdata));
break;
case SYSCTLTYPE_ULONG:
fprintf(fp, "%lu ", *(unsigned long*)(pdata));
break;
case SYSCTLTYPE_INT:
default:
fprintf(fp, "%i ", *(int*)(pdata));
}
if( (entry->flags & 0x00000003) == CTLFLAG_RD )
fprintf(fp, "\t(read only)\n");
else
fprintf(fp, "\n");
skip: ;
}
entry = (struct sysctlhead*)((unsigned char*)entry + entry->blocklen);
}
free(oid);
return 0;
}
//fallback for invalid options
return -1;
#else /* __linux__ */
FILE *fp;
char *basename = "/sys/module/ipfw_mod/parameters/";
char filename[256]; /* full filename */
char *varp;
int ret = 0; /* return value */
int d;
if (name == NULL) /* XXX set errno */
return -1;
/* locate the filename */
varp = strrchr(name, '.');
if (varp == NULL) /* XXX set errno */
return -1;
snprintf(filename, sizeof(filename), "%s%s", basename, varp+1);
/*
* XXX we could open the file here, in rw mode
* but need to check if a file have write
* permissions.
*/
/* check parameters */
if (oldp && oldlenp) { /* read mode */
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "%s fopen error reading filename %s\n", __FUNCTION__, filename);
return -1;
}
if (*oldlenp == 4) {
if (fscanf(fp, "%d", &d) == 1)
memcpy(oldp, &d, *oldlenp);
else
ret = -1;
}
fclose(fp);
}
if (newp && newlen) { /* write */
fp = fopen(filename, "w");
if (fp == NULL) {
fprintf(stderr, "%s fopen error writing filename %s\n", __FUNCTION__, filename);
return -1;
}
if (newlen == 4) {
if (fprintf(fp, "%d", *(int*)newp) < 1)
ret = -1;
}
fclose(fp);
}
return ret;
#endif /* __linux__ */
}
/*
* The following two functions implement getsockopt/setsockopt
* replacements to talk over a TCP socket.
* Because the calls are synchronous, we can run blocking code
* and do not need to play special tricks to be selectable.
* The wire protocol for the emulation is the following:
* REQUEST: n32 req_size, level, optname; u8 data[req_size]
* RESPONSE: n32 resp_size, ret_code; u8 data[resp_size]
* data is only present if ret_code == 0
*
* Return 0 if the message wan sent to the remote
* endpoint, -1 on error.
*
* If the required lenght is greater then the
* available buffer size, -1 is returned and
* optlen is the required lenght.
*/
enum sock_type {GET_SOCKOPT, SET_SOCKOPT};
struct wire_hdr {
uint32_t optlen; /* actual data len */
uint32_t level; /* or error */
uint32_t optname; /* or act len */
uint32_t dir; /* in or out */
};
/* do a complete write of the buffer */
static int
writen(int fd, const char *buf, int len)
{
int i;
for (; len > 0; buf += i, len -= i) {
i = write(fd, buf, len);
ND("have %d wrote %d", len, i);
if (i < 0) {
if (errno == EAGAIN)
continue;
return -1;
}
}
return 0;
}
/* do a complete read */
static int
readn(int fd, char *buf, int len)
{
int i, pos;
for (pos = 0; pos < len; pos += i) {
i = read(fd, buf + pos, len - pos);
ND("have %d want %d got %d", pos, len, i);
if (i < 0) {
if (errno == EAGAIN)
continue;
return -1;
}
}
ND("full read got %d", pos);
return 0;
}
int
__sockopt2(int s, int level, int optname, void *optval, socklen_t *optlen,
enum sopt_dir dir)
{
struct wire_hdr r;
int len = optlen && optval ? *optlen : 0;
int new_errno;
ND("dir %d optlen %d level %d optname %d", dir, len, level, optname);
/* send request to the server */
r.optlen = htonl(len);
r.level = htonl(level);
r.optname = htonl(optname);
r.dir = htonl(dir);
if (writen(s, (const char *) &r, sizeof(r)))
return -1; /* error writing */
/* send data, if present */
if (len < 0) {
fprintf(stderr, "%s invalid args found\n", __FUNCTION__);
return -1;
} else if (len > 0) {
if (writen(s, optval, len))
return -1; /* error writing */
}
/* read response size and error code */
if (readn(s, (char *)&r, sizeof(r)))
return -1; /* error reading */
len = ntohl(r.optlen);
ND("got header, datalen %d", len);
if (len > 0) {
if (readn(s, optval, len)) {
return -1; /* error reading */
}
}
if (optlen)
*optlen = ntohl(r.optlen); /* actual len */
new_errno = ntohl(r.level);
if (new_errno)
errno = new_errno;
return (new_errno ? -1 : 0);
}
/*
* getsockopt() replacement.
*/
int
getsockopt2(int s, int level, int optname, void *optval,
socklen_t *optlen)
{
return __sockopt2(s, level, optname, optval, optlen, SOPT_GET);
}
/*
* setsockopt() replacement
*/
int
setsockopt2(int s, int level, int optname, void *optval,
socklen_t optlen)
{
/* optlen not changed, use the local address */
return __sockopt2(s, level, optname, optval, &optlen, SOPT_SET);
}
#ifdef socket
#undef socket /* we want the real one */
#endif
/*
* This function replaces the socket() call to connect to
* the ipfw control socket.
* We actually ignore the paramerers if IPFW_HOST and IPFW_PORT
* are defined.
*/
int
do_connect(const char *addr, int port)
{
int conn_fd;
/* open the socket */
#ifdef NETLINK
struct rtnl_handle rth;
conn_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
#else
struct sockaddr_in server; /* server address */
const char *s;
conn_fd = socket(AF_INET, SOCK_STREAM, 0);
if (conn_fd < 0) {
perror("socket");
return -1;
}
#endif
#ifndef NETLINK
/* fill the sockaddr structure with server address */
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
/* override the host if set in the environment */
s = getenv("IPFW_HOST");
if (s)
addr = s;
inet_aton(addr, &server.sin_addr);
s = getenv("IPFW_PORT");
if (s && atoi(s) > 0)
port = atoi(s);
server.sin_port = htons(port);
/* connect to the server */
if (connect(conn_fd, (struct sockaddr*) &server, sizeof(server)) < 0) {
perror("connect");
return -1;
}
#ifdef setsockopt /* we want the real one here */
#undef setsockopt
#undef getsockopt
#endif
{
int on = 1, ret;
ret = setsockopt(conn_fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
ND("set TCP_NODELAY %d returns %d", on, ret);
}
if (0)
fprintf(stderr, "connected to %s:%d\n",
inet_ntoa(server.sin_addr), ntohs(server.sin_port));
#endif
return conn_fd;
}

488
lib/ipfw/glue.h Normal file
View File

@ -0,0 +1,488 @@
/*
* Copyright (c) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: glue.h 8327 2011-03-22 17:01:35Z marta $
*
* glue code to adapt the FreeBSD version to linux and windows,
* userland and kernel.
* This is included before any other headers, so we do not have
* a chance to override any #define that should appear in other
* headers.
* First handle headers for userland and kernel. Then common code
* (including headers that require a specific order of inclusion),
* then the user- and kernel- specific parts.
*/
#ifndef _GLUE_H
#define _GLUE_H
/*
* common definitions to allow portability
*/
#ifndef __FBSDID
#define __FBSDID(x) struct __hack
#endif /* FBSDID */
#include <stdint.h> /* linux needs it in addition to sys/types.h */
#include <sys/types.h> /* for size_t */
#define true 1 /* stdbool */
#ifdef _KERNEL /* prevent a warning */
#undef _KERNEL
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h> /* we want errno */
#define _KERNEL
#else
#include <sys/ioctl.h>
#endif
#include <time.h>
#ifndef USERSPACE
#include <netinet/ether.h>
#endif
/*----- */
/* ipfw2.c - from timeconv.h */
static __inline time_t
_long_to_time(long tlong)
{
if (sizeof(long) == sizeof(__int32_t))
return((time_t)(__int32_t)(tlong));
return((time_t)tlong);
}
#define min(a, b) ((a) < (b) ? (a) : (b) ) // radix.c
/*
* debugging macros from ip_dn_private.h
*/
#include <sys/time.h>
#include <stdio.h>
extern char *strrchr(const char *, int);
static inline const char *xyz(const char *s) {
static char buf[128];
struct timeval t;
const char *ret = strrchr(s, '/');
if (ret) s = ret + 1;
gettimeofday(&t, NULL);
buf[sizeof(buf) - 1] = '\0';
snprintf(buf, sizeof(buf), "[%4d.%06d] %s",
(int)(t.tv_sec % 1000), (int)(t.tv_usec), s);
return buf;
}
#define ND(fmt, ...) do {} while (0)
#define D1(fmt, ...) do {} while (0)
#define D(fmt, ...) fprintf(stderr, "%s:%-10s [%d] " fmt "\n", \
xyz(__FILE__), __FUNCTION__, __LINE__, ## __VA_ARGS__)
/* Rate limited version of "D", lps indicates how many per second */
#define RD(lps, format, ...) \
do { \
static int t0, __cnt; \
struct timeval __xxts; \
gettimeofday(&__xxts, NULL); \
if (t0 != __xxts.tv_sec) { \
t0 = __xxts.tv_sec; \
__cnt = 0; \
} \
if (__cnt++ < lps) { \
D(format, ##__VA_ARGS__); \
} \
} while (0)
#define DX(lev, fmt, ...) do { \
if (dn_cfg.debug > lev) D(fmt, ## __VA_ARGS__); } while (0)
/* end debugging macros */
/*
* sbin/ipfw on non-freebsd platform
*/
#ifdef NEED_STRTONUM
/* prototypes from libutil */
/* humanize_number(3) */
#define HN_DECIMAL 0x01
#define HN_NOSPACE 0x02
#define HN_B 0x04
#define HN_DIVISOR_1000 0x08
#define HN_IEC_PREFIXES 0x10
#define HN_GETSCALE 0x10
#define HN_AUTOSCALE 0x20
int humanize_number(char *_buf, size_t _len, int64_t _number,
const char *_suffix, int _scale, int _flags);
int expand_number(const char *buf, uint64_t *num);
long long
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
#ifndef __APPLE__
int ishexnumber(int c);
#endif
#endif /* NEED_STRTONUM */
#ifdef NEED_SYSCTLBYNAME /* and other linux calls */
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
void *newp, size_t newlen);
#define setprogname(x) /* not present in linux */
extern int optreset; /* not present in linux */
long long int strtonum(const char *nptr, long long minval,
long long maxval, const char **errstr);
struct ether_addr;
struct ether_addr * ether_aton(const char *a);
#define ICMP6_MAXTYPE 201
#define __u6_addr in6_u
#define in6_u __in6_u /* missing type for ipv6 (linux 2.6.28) */
#define __u6_addr32 u6_addr32
/* on freebsd sys/socket.h pf specific */
#define NET_RT_IFLIST 3 /* survey interface list */
#define RTM_VERSION 5 /* Up the ante and ignore older versions */
#endif // NEED_SYSCTLBYNAME
#ifdef NEED_SIN_LEN
/*
* linux at least does not have sin_len and sin6_len, so we remap
* to some safe fields (check use of sin6_flowinfo XXX)
*/
#define sin_len sin_zero[0]
#define sin6_len sin6_flowinfo
#endif /* NEED_SIN_LEN */
#ifdef NEED_ROUNDUP2 /* in freensd is in sys/param.h */
/* round up to the next power of 2 (y) */
#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
#endif // NEED_ROUNDUP2
/* possibly redundant, does not harm */
size_t strlcpy(char * dst, const char * src, size_t siz);
/*
* Part 2: common userland and kernel definitions
*/
#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
#define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */
#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */
#define ICMP6_DST_UNREACH_NOPORT 4 /* port unreachable */
/*
* linux: sysctl are mapped into /sys/module/ipfw_mod parameters
* windows: they are emulated via get/setsockopt
*/
#define CTLFLAG_RD 1
#define CTLFLAG_RDTUN 1
#define CTLFLAG_RW 2
#define CTLFLAG_SECURE3 0 /* unsupported */
#define CTLFLAG_VNET 0 /* unsupported */
/* if needed, queue.h must be included here after list.h */
/*
* our own struct thread
*/
struct thread { /* ip_fw_sockopt */
void *sopt_td;
void *td_ucred;
};
enum sopt_dir { SOPT_GET, SOPT_SET };
struct sockopt {
enum sopt_dir sopt_dir; /* is this a get or a set? */
int sopt_level; /* second arg of [gs]etsockopt */
int sopt_name; /* third arg of [gs]etsockopt */
void *sopt_val; /* fourth arg of [gs]etsockopt */
size_t sopt_valsize; /* (almost) fifth arg of [gs]etsockopt */
struct thread *sopt_td; /* calling thread or null if kernel */
};
/*
* List of values used for set/getsockopt options.
* The base value on FreeBSD is defined as a macro,
* if not available we will use our own enum.
* The TABLE_BASE value is used in the kernel.
*/
#define _IPFW_SOCKOPT_BASE 100 /* 40 on freebsd */
#define IP_FW_TABLE_ADD (_IPFW_SOCKOPT_BASE + 0)
#define IP_FW_TABLE_DEL (_IPFW_SOCKOPT_BASE + 1)
#define IP_FW_TABLE_FLUSH (_IPFW_SOCKOPT_BASE + 2)
#define IP_FW_TABLE_GETSIZE (_IPFW_SOCKOPT_BASE + 3)
#define IP_FW_TABLE_LIST (_IPFW_SOCKOPT_BASE + 4)
#define IP_FW_DYN_GET (_IPFW_SOCKOPT_BASE + 5)
#define IP_FW3 (_IPFW_SOCKOPT_BASE + 8)
#define IP_DUMMYNET3 (_IPFW_SOCKOPT_BASE + 9)
#define IP_FW_ADD (_IPFW_SOCKOPT_BASE + 10)
#define IP_FW_DEL (_IPFW_SOCKOPT_BASE + 11)
#define IP_FW_FLUSH (_IPFW_SOCKOPT_BASE + 12)
#define IP_FW_ZERO (_IPFW_SOCKOPT_BASE + 13)
#define IP_FW_GET (_IPFW_SOCKOPT_BASE + 14)
#define IP_FW_RESETLOG (_IPFW_SOCKOPT_BASE + 15)
#define IP_FW_NAT_CFG (_IPFW_SOCKOPT_BASE + 16)
#define IP_FW_NAT_DEL (_IPFW_SOCKOPT_BASE + 17)
#define IP_FW_NAT_GET_CONFIG (_IPFW_SOCKOPT_BASE + 18)
#define IP_FW_NAT_GET_LOG (_IPFW_SOCKOPT_BASE + 19)
#define IP_DUMMYNET_CONFIGURE (_IPFW_SOCKOPT_BASE + 20)
#define IP_DUMMYNET_DEL (_IPFW_SOCKOPT_BASE + 21)
#define IP_DUMMYNET_FLUSH (_IPFW_SOCKOPT_BASE + 22)
/* 63 is missing */
#define IP_DUMMYNET_GET (_IPFW_SOCKOPT_BASE + 24)
#define _IPFW_SOCKOPT_END (_IPFW_SOCKOPT_BASE + 25)
/*
* Part 3: userland stuff for linux/windows
*/
/*
* now remap functions for userland or linux kernel etc.
*/
#ifdef USERSPACE
/*
* definitions used when the programs communicate through userspace.
* We need to define the socket and addresses used to talk, and
* the userland side must also remap socket() and [gs]etsockopt()
* to appropriate wrappers.
*/
#define LOCALADDR "127.0.0.1"
#define IPFW_PORT 5555
#ifndef KERNEL_SIDE
#ifdef _KERNEL
#error _KERNEL defined in user space
#endif
int do_connect(const char *addr, int port);
#include <sys/socket.h> /* for socklen_t */
#define socket(a, b, c) do_connect(LOCALADDR, IPFW_PORT)
#define setsockopt setsockopt2
#define getsockopt getsockopt2
int getsockopt2(int s, int lev, int optname, void *optval, socklen_t *optlen);
int setsockopt2(int s, int lev, int optname, void *optval, socklen_t optlen);
#endif /* KERNEL_SIDE */
#endif /* USERSPACE */
/*
* Part 5: windows specific stuff and sysctl emulation
*/
/*******************
* SYSCTL emulation *
********************/
#ifdef EMULATE_SYSCTL
/* this needs to be here, as it is part of the user-kernel messages */
/* flag is set with the last 2 bits for access, as defined in glue.h
* and the rest for type
*/
enum {
SYSCTLTYPE_INT = 0,
SYSCTLTYPE_UINT = 1,
SYSCTLTYPE_SHORT = 2,
SYSCTLTYPE_USHORT = 3,
SYSCTLTYPE_LONG = 4,
SYSCTLTYPE_ULONG = 5,
SYSCTLTYPE_STRING = 6,
/* the following are SYSCTL_PROC equivalents of the above,
* where the SYSCTLTYPE is shifted 2 bits,
* and SYSCTLTYPE_PROC is set
*/
SYSCTLTYPE_PROC = 0x100,
CTLTYPE_INT = (0x100 | (0<<2)),
CTLTYPE_UINT = (0x100 | (1<<2)),
CTLTYPE_LONG = (0x100 | (4<<2)),
CTLTYPE_ULONG = (0x100 | (5<<2))
};
struct sysctlhead {
uint32_t blocklen; //total size of the entry
uint32_t namelen; //strlen(name) + '\0'
uint32_t flags; //type and access
uint32_t datalen;
};
#endif /* EMULATE_SYSCTL */
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t newlen);
#ifndef __FreeBSD__
#define test_bit(ix, pData) ((*pData) & (1<<(ix)))
#define __set_bit(ix, pData) (*pData) |= (1<<(ix))
#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix))
static inline int fls(int _n)
{
unsigned int n = _n;
int i = 0;
for (i = 0; n > 0; n >>= 1, i++)
;
return i;
}
static inline unsigned long __fls(unsigned long word)
{
return fls(word) - 1;
}
#endif /* !FreeBSD */
#ifdef KERNEL_SIDE
/* sys/counter.h , to be moved to a file */
typedef uint64_t *counter_u64_t; // XXX kernel
static inline void counter_u64_add(counter_u64_t c, int64_t v)
{
*c += v;
}
static inline void counter_u64_zero(counter_u64_t c)
{
*c = 0;
}
static inline uint64_t counter_u64_fetch(counter_u64_t c)
{
return *c;
}
struct rm_priotracker {
};
#define vslock(_a, _b) (0)
#define vsunlock(_a, _b)
typedef uint64_t u_register_t; // XXX not on osx ?
typedef uintptr_t eventhandler_tag;
#define EVENTHANDLER_REGISTER(_a, _b, ...) (uintptr_t)_b;
#define EVENTHANDLER_DEREGISTER(_a, _b, ...) (void)_b;
// XXX this needs to be completed
#define if_name(_ifp) (_ifp->if_xname)
#define ifunit_ref(_n) NULL // XXX
#define if_rele(_n)
#define rtalloc1_fib(_a, ...) NULL
#define rt_key(_a) NULL
#define rt_mask(_a) NULL
#define RTFREE_LOCKED(_a) ((void)NULL)
struct rtentry {
};
#define rt_tables_get_rnh(_a, _b) NULL
#endif /* KERNEL_SIDE */
#ifdef _KERNEL
/* XXX kernel support */
/* on freebsd net/if.h XXX used */
#ifdef linux
#define div64(a,b) (((int64_t)a)/((int64_t)b))
#define LINUX_VERSION_CODE 30003
#define KERNEL_VERSION(a,b,c) (a*10000+b*100 + c)
#define __printflike(a,b)
#endif /* linux */
#endif /* _KERNEL */
#ifndef __FreeBSD__
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#include "missing.h"
struct if_data {
/* ... */
u_long ifi_mtu; /* maximum transmission unit */
};
#endif
#ifdef __APPLE__
#include <sys/socketvar.h> // need in kernel
/* needed both in kernel and userspace */
struct if_data64 { // XXX Darwin version
/* ... */
u_long ifi_mtu; /* maximum transmission unit */
};
struct net_event_data {
};
struct in_addr;
#endif /* __APPLE__ */
#define __PAST_END(v, idx) v[idx]
/*
* a fast copy routine
*/
#include <strings.h>
// XXX only for multiples of 64 bytes, non overlapped.
static inline void
_pkt_copy(const void *_src, void *_dst, int l)
{
const uint64_t *src = _src;
uint64_t *dst = _dst;
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
if (unlikely(l >= 1024)) {
bcopy(src, dst, l);
return;
}
for (; l > 0; l-=64) {
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
}
}
#endif /* !_GLUE_H */

167
lib/ipfw/humanize_number.c Normal file
View File

@ -0,0 +1,167 @@
/* $NetBSD: humanize_number.c,v 1.14 2008/04/28 20:22:59 martin Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: head/lib/libutil/humanize_number.c 220582 2011-04-12 22:48:03Z delphij $");
#include <sys/types.h>
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
//#include <libutil.h>
static const int maxscale = 7;
int
humanize_number(char *buf, size_t len, int64_t quotient,
const char *suffix, int scale, int flags)
{
const char *prefixes, *sep;
int i, r, remainder, s1, s2, sign;
int64_t divisor, max;
size_t baselen;
assert(buf != NULL);
assert(suffix != NULL);
assert(scale >= 0);
assert(scale < maxscale || (((scale & (HN_AUTOSCALE | HN_GETSCALE)) != 0)));
assert(!((flags & HN_DIVISOR_1000) && (flags & HN_IEC_PREFIXES)));
remainder = 0;
if (flags & HN_IEC_PREFIXES) {
baselen = 2;
/*
* Use the prefixes for power of two recommended by
* the International Electrotechnical Commission
* (IEC) in IEC 80000-3 (i.e. Ki, Mi, Gi...).
*
* HN_IEC_PREFIXES implies a divisor of 1024 here
* (use of HN_DIVISOR_1000 would have triggered
* an assertion earlier).
*/
divisor = 1024;
if (flags & HN_B)
prefixes = "B\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
else
prefixes = "\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
} else {
baselen = 1;
if (flags & HN_DIVISOR_1000)
divisor = 1000;
else
divisor = 1024;
if (flags & HN_B)
prefixes = "B\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
else
prefixes = "\0\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
}
#define SCALE2PREFIX(scale) (&prefixes[(scale) * 3])
if (scale < 0 || (scale >= maxscale &&
(scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0))
return (-1);
if (buf == NULL || suffix == NULL)
return (-1);
if (len > 0)
buf[0] = '\0';
if (quotient < 0) {
sign = -1;
quotient = -quotient;
baselen += 2; /* sign, digit */
} else {
sign = 1;
baselen += 1; /* digit */
}
if (flags & HN_NOSPACE)
sep = "";
else {
sep = " ";
baselen++;
}
baselen += strlen(suffix);
/* Check if enough room for `x y' + suffix + `\0' */
if (len < baselen + 1)
return (-1);
if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
/* See if there is additional columns can be used. */
for (max = 1, i = len - baselen; i-- > 0;)
max *= 10;
/*
* Divide the number until it fits the given column.
* If there will be an overflow by the rounding below,
* divide once more.
*/
for (i = 0;
(quotient >= max || (quotient == max - 1 && remainder >= 950)) &&
i < maxscale; i++) {
remainder = quotient % divisor;
quotient /= divisor;
}
if (scale & HN_GETSCALE)
return (i);
} else {
for (i = 0; i < scale && i < maxscale; i++) {
remainder = quotient % divisor;
quotient /= divisor;
}
}
/* If a value <= 9.9 after rounding and ... */
if (quotient <= 9 && remainder < 950 && i > 0 && flags & HN_DECIMAL) {
/* baselen + \0 + .N */
if (len < baselen + 1 + 2)
return (-1);
s1 = (int)quotient + ((remainder + 50) / 1000);
s2 = ((remainder + 50) / 100) % 10;
r = snprintf(buf, len, "%d%s%d%s%s%s",
sign * s1, localeconv()->decimal_point, s2,
sep, SCALE2PREFIX(i), suffix);
} else
r = snprintf(buf, len, "%" PRId64 "%s%s%s",
sign * (quotient + (remainder + 50) / 1000),
sep, SCALE2PREFIX(i), suffix);
return (r);
}

4968
lib/ipfw/ipfw2.c Normal file

File diff suppressed because it is too large Load Diff

352
lib/ipfw/ipfw2.h Normal file
View File

@ -0,0 +1,352 @@
/*
* Copyright (c) 2002-2003 Luigi Rizzo
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
* Copyright (c) 1994 Ugen J.S.Antsilevich
*
* Idea and grammar partially left from:
* Copyright (c) 1993 Daniel Boulet
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
*
* Redistribution in binary form may occur without any restrictions.
* Obviously, it would be nice if you gave credit where credit is due
* but requiring it would be too onerous.
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
* NEW command line interface for IP firewall facility
*
* $FreeBSD: head/sbin/ipfw/ipfw2.h 272840 2014-10-09 19:32:35Z melifaro $
*/
/*
* Options that can be set on the command line.
* When reading commands from a file, a subset of the options can also
* be applied globally by specifying them before the file name.
* After that, each line can contain its own option that changes
* the global value.
* XXX The context is not restored after each line.
*/
struct cmdline_opts {
/* boolean options: */
int do_value_as_ip; /* show table value as IP */
int do_resolv; /* try to resolve all ip to names */
int do_time; /* Show time stamps */
int do_quiet; /* Be quiet in add and flush */
int do_pipe; /* this cmd refers to a pipe/queue/sched */
int do_nat; /* this cmd refers to a nat config */
int do_dynamic; /* display dynamic rules */
int do_expired; /* display expired dynamic rules */
int do_compact; /* show rules in compact mode */
int do_force; /* do not ask for confirmation */
int show_sets; /* display the set each rule belongs to */
int test_only; /* only check syntax */
int comment_only; /* only print action and comment */
int verbose; /* be verbose on some commands */
/* The options below can have multiple values. */
int do_sort; /* field to sort results (0 = no) */
/* valid fields are 1 and above */
int use_set; /* work with specified set number */
/* 0 means all sets, otherwise apply to set use_set - 1 */
};
extern struct cmdline_opts co;
/*
* _s_x is a structure that stores a string <-> token pairs, used in
* various places in the parser. Entries are stored in arrays,
* with an entry with s=NULL as terminator.
* The search routines are match_token() and match_value().
* Often, an element with x=0 contains an error string.
*
*/
struct _s_x {
char const *s;
int x;
};
extern struct _s_x f_ipdscp[];
enum tokens {
TOK_NULL=0,
TOK_OR,
TOK_NOT,
TOK_STARTBRACE,
TOK_ENDBRACE,
TOK_ACCEPT,
TOK_COUNT,
TOK_PIPE,
TOK_LINK,
TOK_QUEUE,
TOK_FLOWSET,
TOK_SCHED,
TOK_DIVERT,
TOK_TEE,
TOK_NETGRAPH,
TOK_NGTEE,
TOK_FORWARD,
TOK_SKIPTO,
TOK_DENY,
TOK_REJECT,
TOK_RESET,
TOK_UNREACH,
TOK_CHECKSTATE,
TOK_NAT,
TOK_REASS,
TOK_CALL,
TOK_RETURN,
TOK_ALTQ,
TOK_LOG,
TOK_TAG,
TOK_UNTAG,
TOK_TAGGED,
TOK_UID,
TOK_GID,
TOK_JAIL,
TOK_IN,
TOK_LIMIT,
TOK_KEEPSTATE,
TOK_LAYER2,
TOK_OUT,
TOK_DIVERTED,
TOK_DIVERTEDLOOPBACK,
TOK_DIVERTEDOUTPUT,
TOK_XMIT,
TOK_RECV,
TOK_VIA,
TOK_FRAG,
TOK_IPOPTS,
TOK_IPLEN,
TOK_IPID,
TOK_IPPRECEDENCE,
TOK_DSCP,
TOK_IPTOS,
TOK_IPTTL,
TOK_IPVER,
TOK_ESTAB,
TOK_SETUP,
TOK_TCPDATALEN,
TOK_TCPFLAGS,
TOK_TCPOPTS,
TOK_TCPSEQ,
TOK_TCPACK,
TOK_TCPWIN,
TOK_ICMPTYPES,
TOK_MAC,
TOK_MACTYPE,
TOK_VERREVPATH,
TOK_VERSRCREACH,
TOK_ANTISPOOF,
TOK_IPSEC,
TOK_COMMENT,
TOK_PLR,
TOK_NOERROR,
TOK_BUCKETS,
TOK_DSTIP,
TOK_SRCIP,
TOK_DSTPORT,
TOK_SRCPORT,
TOK_ALL,
TOK_MASK,
TOK_FLOW_MASK,
TOK_SCHED_MASK,
TOK_BW,
TOK_DELAY,
TOK_PROFILE,
TOK_BURST,
TOK_RED,
TOK_GRED,
TOK_ECN,
TOK_DROPTAIL,
TOK_PROTO,
/* dummynet tokens */
TOK_WEIGHT,
TOK_LMAX,
TOK_PRI,
TOK_TYPE,
TOK_SLOTSIZE,
TOK_IP,
TOK_IF,
TOK_ALOG,
TOK_DENY_INC,
TOK_SAME_PORTS,
TOK_UNREG_ONLY,
TOK_SKIP_GLOBAL,
TOK_RESET_ADDR,
TOK_ALIAS_REV,
TOK_PROXY_ONLY,
TOK_REDIR_ADDR,
TOK_REDIR_PORT,
TOK_REDIR_PROTO,
TOK_IPV6,
TOK_FLOWID,
TOK_ICMP6TYPES,
TOK_EXT6HDR,
TOK_DSTIP6,
TOK_SRCIP6,
TOK_IPV4,
TOK_UNREACH6,
TOK_RESET6,
TOK_FIB,
TOK_SETFIB,
TOK_LOOKUP,
TOK_SOCKARG,
TOK_SETDSCP,
TOK_FLOW,
TOK_IFLIST,
/* Table tokens */
TOK_CREATE,
TOK_DESTROY,
TOK_LIST,
TOK_INFO,
TOK_DETAIL,
TOK_MODIFY,
TOK_FLUSH,
TOK_SWAP,
TOK_ADD,
TOK_DEL,
TOK_VALTYPE,
TOK_ALGO,
TOK_TALIST,
TOK_ATOMIC,
TOK_LOCK,
TOK_UNLOCK,
TOK_VLIST,
};
/*
* the following macro returns an error message if we run out of
* arguments.
*/
#define NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);}
#define NEED1(msg) {if (!(*av)) errx(EX_USAGE, msg);}
struct buf_pr {
char *buf; /* allocated buffer */
char *ptr; /* current pointer */
size_t size; /* total buffer size */
size_t avail; /* available storage */
size_t needed; /* length needed */
};
int pr_u64(struct buf_pr *bp, uint64_t *pd, int width);
int bp_alloc(struct buf_pr *b, size_t size);
void bp_free(struct buf_pr *b);
int bprintf(struct buf_pr *b, char *format, ...);
/* memory allocation support */
void *safe_calloc(size_t number, size_t size);
void *safe_realloc(void *ptr, size_t size);
/* string comparison functions used for historical compatibility */
int _substrcmp(const char *str1, const char* str2);
int _substrcmp2(const char *str1, const char* str2, const char* str3);
int stringnum_cmp(const char *a, const char *b);
/* utility functions */
int match_token(struct _s_x *table, char *string);
int match_token_relaxed(struct _s_x *table, char *string);
char const *match_value(struct _s_x *p, int value);
size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table,
char *delimiter);
int fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
uint32_t *clear);
void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set);
struct _ip_fw3_opheader;
int do_cmd(int optname, void *optval, uintptr_t optlen);
int do_set3(int optname, struct _ip_fw3_opheader *op3, uintptr_t optlen);
int do_get3(int optname, struct _ip_fw3_opheader *op3, size_t *optlen);
struct in6_addr;
void n2mask(struct in6_addr *mask, int n);
int contigmask(uint8_t *p, int len);
/*
* Forward declarations to avoid include way too many headers.
* C does not allow duplicated typedefs, so we use the base struct
* that the typedef points to.
* Should the typedefs use a different type, the compiler will
* still detect the change when compiling the body of the
* functions involved, so we do not lose error checking.
*/
struct _ipfw_insn;
struct _ipfw_insn_altq;
struct _ipfw_insn_u32;
struct _ipfw_insn_ip6;
struct _ipfw_insn_icmp6;
/*
* The reserved set numer. This is a constant in ip_fw.h
* but we store it in a variable so other files do not depend
* in that header just for one constant.
*/
extern int resvd_set_number;
/* first-level command handlers */
void ipfw_add(char *av[]);
void ipfw_show_nat(int ac, char **av);
void ipfw_config_pipe(int ac, char **av);
void ipfw_config_nat(int ac, char **av);
void ipfw_sets_handler(char *av[]);
void ipfw_table_handler(int ac, char *av[]);
void ipfw_sysctl_handler(char *av[], int which);
void ipfw_delete(char *av[]);
void ipfw_flush(int force);
void ipfw_zero(int ac, char *av[], int optname);
void ipfw_list(int ac, char *av[], int show_counters);
void ipfw_internal_handler(int ac, char *av[]);
#ifdef PF
/* altq.c */
void altq_set_enabled(int enabled);
u_int32_t altq_name_to_qid(const char *name);
void print_altq_cmd(struct buf_pr *bp, struct _ipfw_insn_altq *altqptr);
#else
#define NO_ALTQ
#endif
/* dummynet.c */
void dummynet_list(int ac, char *av[], int show_counters);
void dummynet_flush(void);
int ipfw_delete_pipe(int pipe_or_queue, int n);
/* ipv6.c */
void print_unreach6_code(uint16_t code);
void print_ip6(struct buf_pr *bp, struct _ipfw_insn_ip6 *cmd, char const *s);
void print_flow6id(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd);
void print_icmp6types(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd);
void print_ext6hdr(struct buf_pr *bp, struct _ipfw_insn *cmd );
struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen);
struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen);
void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
void fill_unreach6_code(u_short *codep, char *str);
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
/* tables.c */
struct _ipfw_obj_ctlv;
char *table_search_ctlv(struct _ipfw_obj_ctlv *ctlv, uint16_t idx);
void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv);
int table_check_name(char *tablename);
void ipfw_list_ta(int ac, char *av[]);
void ipfw_list_values(int ac, char *av[]);

536
lib/ipfw/ipv6.c Normal file
View File

@ -0,0 +1,536 @@
/*
* Copyright (c) 2002-2003 Luigi Rizzo
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
* Copyright (c) 1994 Ugen J.S.Antsilevich
*
* Idea and grammar partially left from:
* Copyright (c) 1993 Daniel Boulet
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
*
* Redistribution in binary form may occur without any restrictions.
* Obviously, it would be nice if you gave credit where credit is due
* but requiring it would be too onerous.
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
* NEW command line interface for IP firewall facility
*
* $FreeBSD: head/sbin/ipfw/ipv6.c 270424 2014-08-23 17:37:18Z melifaro $
*
* ipv6 support
*/
#include <sys/types.h>
#include <sys/socket.h>
#include "ipfw2.h"
#include <err.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/icmp6.h>
#include <netinet/ip_fw.h>
#include <arpa/inet.h>
#define CHECK_LENGTH(v, len) do { \
if ((v) < (len)) \
errx(EX_DATAERR, "Rule too long"); \
} while (0)
static struct _s_x icmp6codes[] = {
{ "no-route", ICMP6_DST_UNREACH_NOROUTE },
{ "admin-prohib", ICMP6_DST_UNREACH_ADMIN },
{ "address", ICMP6_DST_UNREACH_ADDR },
{ "port", ICMP6_DST_UNREACH_NOPORT },
{ NULL, 0 }
};
void
fill_unreach6_code(u_short *codep, char *str)
{
int val;
char *s;
val = strtoul(str, &s, 0);
if (s == str || *s != '\0' || val >= 0x100)
val = match_token(icmp6codes, str);
if (val < 0)
errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
*codep = val;
return;
}
void
print_unreach6_code(uint16_t code)
{
char const *s = match_value(icmp6codes, code);
if (s != NULL)
printf("unreach6 %s", s);
else
printf("unreach6 %u", code);
}
/*
* Print the ip address contained in a command.
*/
void
print_ip6(struct buf_pr *bp, ipfw_insn_ip6 *cmd, char const *s)
{
struct hostent *he = NULL;
int len = F_LEN((ipfw_insn *) cmd) - 1;
struct in6_addr *a = &(cmd->addr6);
char trad[255];
bprintf(bp, "%s%s ", cmd->o.len & F_NOT ? " not": "", s);
if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
bprintf(bp, "me6");
return;
}
if (cmd->o.opcode == O_IP6) {
bprintf(bp, " ip6");
return;
}
/*
* len == 4 indicates a single IP, whereas lists of 1 or more
* addr/mask pairs have len = (2n+1). We convert len to n so we
* use that to count the number of entries.
*/
for (len = len / 4; len > 0; len -= 2, a += 2) {
int mb = /* mask length */
(cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ?
128 : contigmask((uint8_t *)&(a[1]), 128);
if (mb == 128 && co.do_resolv)
he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);
if (he != NULL) /* resolved to name */
bprintf(bp, "%s", he->h_name);
else if (mb == 0) /* any */
bprintf(bp, "any");
else { /* numeric IP followed by some kind of mask */
if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL)
bprintf(bp, "Error ntop in print_ip6\n");
bprintf(bp, "%s", trad );
if (mb < 0) /* XXX not really legal... */
bprintf(bp, ":%s",
inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
else if (mb < 128)
bprintf(bp, "/%d", mb);
}
if (len > 2)
bprintf(bp, ",");
}
}
void
fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
{
uint8_t type;
CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6));
bzero(cmd, sizeof(*cmd));
while (*av) {
if (*av == ',')
av++;
type = strtoul(av, &av, 0);
if (*av != ',' && *av != '\0')
errx(EX_DATAERR, "invalid ICMP6 type");
/*
* XXX: shouldn't this be 0xFF? I can't see any reason why
* we shouldn't be able to filter all possiable values
* regardless of the ability of the rest of the kernel to do
* anything useful with them.
*/
if (type > ICMP6_MAXTYPE)
errx(EX_DATAERR, "ICMP6 type out of range");
cmd->d[type / 32] |= ( 1 << (type % 32));
}
cmd->o.opcode = O_ICMP6TYPE;
cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
}
void
print_icmp6types(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
int i, j;
char sep= ' ';
bprintf(bp, " ip6 icmp6types");
for (i = 0; i < 7; i++)
for (j=0; j < 32; ++j) {
if ( (cmd->d[i] & (1 << (j))) == 0)
continue;
bprintf(bp, "%c%d", sep, (i*32 + j));
sep = ',';
}
}
void
print_flow6id(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
uint16_t i, limit = cmd->o.arg1;
char sep = ',';
bprintf(bp, " flow-id ");
for( i=0; i < limit; ++i) {
if (i == limit - 1)
sep = ' ';
bprintf(bp, "%d%c", cmd->d[i], sep);
}
}
/* structure and define for the extension header in ipv6 */
static struct _s_x ext6hdrcodes[] = {
{ "frag", EXT_FRAGMENT },
{ "hopopt", EXT_HOPOPTS },
{ "route", EXT_ROUTING },
{ "dstopt", EXT_DSTOPTS },
{ "ah", EXT_AH },
{ "esp", EXT_ESP },
{ "rthdr0", EXT_RTHDR0 },
{ "rthdr2", EXT_RTHDR2 },
{ NULL, 0 }
};
/* fills command for the extension header filtering */
int
fill_ext6hdr( ipfw_insn *cmd, char *av)
{
int tok;
char *s = av;
cmd->arg1 = 0;
while(s) {
av = strsep( &s, ",") ;
tok = match_token(ext6hdrcodes, av);
switch (tok) {
case EXT_FRAGMENT:
cmd->arg1 |= EXT_FRAGMENT;
break;
case EXT_HOPOPTS:
cmd->arg1 |= EXT_HOPOPTS;
break;
case EXT_ROUTING:
cmd->arg1 |= EXT_ROUTING;
break;
case EXT_DSTOPTS:
cmd->arg1 |= EXT_DSTOPTS;
break;
case EXT_AH:
cmd->arg1 |= EXT_AH;
break;
case EXT_ESP:
cmd->arg1 |= EXT_ESP;
break;
case EXT_RTHDR0:
cmd->arg1 |= EXT_RTHDR0;
break;
case EXT_RTHDR2:
cmd->arg1 |= EXT_RTHDR2;
break;
default:
errx( EX_DATAERR, "invalid option for ipv6 exten header" );
break;
}
}
if (cmd->arg1 == 0 )
return 0;
cmd->opcode = O_EXT_HDR;
cmd->len |= F_INSN_SIZE( ipfw_insn );
return 1;
}
void
print_ext6hdr(struct buf_pr *bp, ipfw_insn *cmd )
{
char sep = ' ';
bprintf(bp, " extension header:");
if (cmd->arg1 & EXT_FRAGMENT ) {
bprintf(bp, "%cfragmentation", sep);
sep = ',';
}
if (cmd->arg1 & EXT_HOPOPTS ) {
bprintf(bp, "%chop options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_ROUTING ) {
bprintf(bp, "%crouting options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_RTHDR0 ) {
bprintf(bp, "%crthdr0", sep);
sep = ',';
}
if (cmd->arg1 & EXT_RTHDR2 ) {
bprintf(bp, "%crthdr2", sep);
sep = ',';
}
if (cmd->arg1 & EXT_DSTOPTS ) {
bprintf(bp, "%cdestination options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_AH ) {
bprintf(bp, "%cauthentication header", sep);
sep = ',';
}
if (cmd->arg1 & EXT_ESP ) {
bprintf(bp, "%cencapsulated security payload", sep);
}
}
/* Try to find ipv6 address by hostname */
static int
lookup_host6 (char *host, struct in6_addr *ip6addr)
{
struct hostent *he;
if (!inet_pton(AF_INET6, host, ip6addr)) {
if ((he = gethostbyname2(host, AF_INET6)) == NULL)
return(-1);
memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
}
return(0);
}
/*
* fill the addr and mask fields in the instruction as appropriate from av.
* Update length as appropriate.
* The following formats are allowed:
* any matches any IP6. Actually returns an empty instruction.
* me returns O_IP6_*_ME
*
* 03f1::234:123:0342 single IP6 addres
* 03f1::234:123:0342/24 address/mask
* 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
*
* Set of address (as in ipv6) not supported because ipv6 address
* are typically random past the initial prefix.
* Return 1 on success, 0 on failure.
*/
static int
fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen)
{
int len = 0;
struct in6_addr *d = &(cmd->addr6);
/*
* Needed for multiple address.
* Note d[1] points to struct in6_add r mask6 of cmd
*/
cmd->o.len &= ~F_LEN_MASK; /* zero len */
if (strcmp(av, "any") == 0)
return (1);
if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
return (1);
}
if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
return (1);
}
if (strncmp(av, "table(", 6) == 0) {
char *p = strchr(av + 6, ',');
uint32_t *dm = ((ipfw_insn_u32 *)cmd)->d;
if (p)
*p++ = '\0';
cmd->o.opcode = O_IP_DST_LOOKUP;
cmd->o.arg1 = strtoul(av + 6, NULL, 0);
if (p) {
cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
dm[0] = strtoul(p, NULL, 0);
} else
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
return (1);
}
av = strdup(av);
while (av) {
/*
* After the address we can have '/' indicating a mask,
* or ',' indicating another address follows.
*/
char *p;
int masklen;
char md = '\0';
CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr));
if ((p = strpbrk(av, "/,")) ) {
md = *p; /* save the separator */
*p = '\0'; /* terminate address string */
p++; /* and skip past it */
}
/* now p points to NULL, mask or next entry */
/* lookup stores address in *d as a side effect */
if (lookup_host6(av, d) != 0) {
/* XXX: failed. Free memory and go */
errx(EX_DATAERR, "bad address \"%s\"", av);
}
/* next, look at the mask, if any */
masklen = (md == '/') ? atoi(p) : 128;
if (masklen > 128 || masklen < 0)
errx(EX_DATAERR, "bad width \"%s\''", p);
else
n2mask(&d[1], masklen);
APPLY_MASK(d, &d[1]) /* mask base address with mask */
/* find next separator */
if (md == '/') { /* find separator past the mask */
p = strpbrk(p, ",");
if (p != NULL)
p++;
}
av = p;
/* Check this entry */
if (masklen == 0) {
/*
* 'any' turns the entire list into a NOP.
* 'not any' never matches, so it is removed from the
* list unless it is the only item, in which case we
* report an error.
*/
if (cmd->o.len & F_NOT && av == NULL && len == 0)
errx(EX_DATAERR, "not any never matches");
continue;
}
/*
* A single IP can be stored alone
*/
if (masklen == 128 && av == NULL && len == 0) {
len = F_INSN_SIZE(struct in6_addr);
break;
}
/* Update length and pointer to arguments */
len += F_INSN_SIZE(struct in6_addr)*2;
d += 2;
} /* end while */
/*
* Total length of the command, remember that 1 is the size of
* the base command.
*/
if (len + 1 > F_LEN_MASK)
errx(EX_DATAERR, "address list too long");
cmd->o.len |= len+1;
free(av);
return (1);
}
/*
* fills command for ipv6 flow-id filtering
* note that the 20 bit flow number is stored in a array of u_int32_t
* it's supported lists of flow-id, so in the o.arg1 we store how many
* additional flow-id we want to filter, the basic is 1
*/
void
fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen)
{
u_int32_t type; /* Current flow number */
u_int16_t nflow = 0; /* Current flow index */
char *s = av;
cmd->d[0] = 0; /* Initializing the base number*/
while (s) {
CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_u32) + nflow + 1);
av = strsep( &s, ",") ;
type = strtoul(av, &av, 0);
if (*av != ',' && *av != '\0')
errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
if (type > 0xfffff)
errx(EX_DATAERR, "flow number out of range %s", av);
cmd->d[nflow] |= type;
nflow++;
}
if( nflow > 0 ) {
cmd->o.opcode = O_FLOW6ID;
cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
cmd->o.arg1 = nflow;
}
else {
errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
}
}
ipfw_insn *
add_srcip6(ipfw_insn *cmd, char *av, int cblen)
{
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
if (cmd->opcode == O_IP_DST_SET) /* set */
cmd->opcode = O_IP_SRC_SET;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
cmd->opcode = O_IP_SRC_LOOKUP;
else if (F_LEN(cmd) == 0) { /* any */
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
cmd->opcode = O_IP6_SRC_ME;
} else if (F_LEN(cmd) ==
(F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
/* single IP, no mask*/
cmd->opcode = O_IP6_SRC;
} else { /* addr/mask opt */
cmd->opcode = O_IP6_SRC_MASK;
}
return cmd;
}
ipfw_insn *
add_dstip6(ipfw_insn *cmd, char *av, int cblen)
{
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
if (cmd->opcode == O_IP_DST_SET) /* set */
;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
;
else if (F_LEN(cmd) == 0) { /* any */
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
cmd->opcode = O_IP6_DST_ME;
} else if (F_LEN(cmd) ==
(F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
/* single IP, no mask*/
cmd->opcode = O_IP6_DST;
} else { /* addr/mask opt */
cmd->opcode = O_IP6_DST_MASK;
}
return cmd;
}

801
lib/ipfw/missing.h Normal file
View File

@ -0,0 +1,801 @@
/*
* Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* $Id: missing.h 8377 2011-04-04 16:08:27Z marta $
*
* Header for kernel variables and functions that are not available in
* userland.
*/
#ifndef _MISSING_H_
#define _MISSING_H_
#define KLD_MODULE /* disable kernel dependencies */
/* defined as assert */
void panic(const char *fmt, ...);
#define KASSERT(exp,msg) do { \
if (__predict_false(!(exp))) \
panic msg; \
} while (0)
/* don't bother to optimize */
#ifndef __predict_false
#define __predict_false(x) (x) /* __builtin_expect((exp), 0) */
#endif // XXX
#ifdef _KERNEL
#define NEED_KERNEL
#undef _KERNEL
#endif
#include <stdio.h> // printf
#include <sys/socket.h> // IFNAMSIZ ?
#include <string.h> // strncmp
#include <stdlib.h> // bsearch
#ifdef NEED_KERNEL
#define _KERNEL
#include <sys/cdefs.h>
#include <sys/param.h>
#define __user // not defined here ?
#define __init
#define __exit
/* portability features, to be set before the rest: */
#define WITHOUT_BPF /* do not use bpf logging */
#define MALLOC_DECLARE(x) struct __hack /* nothing */
// XXX kernel malloc/free
extern void *kern_malloc(int);
extern void kern_free(void *);
#define malloc(_size, type, flags) kern_malloc(_size)
#define free(_var, type) kern_free(_var)
/* inet_ntoa_r() differs in userspace and kernel.
* We load netinet/in.h so we get the kernel prototype ?
* but we also need to put #defines in the two places where
* it is used XXX fixme
*/
#include <netinet/in.h>
/* log() conflicts with the math function.
* Revise, modifying the first argument.
*/
#define LOG_ERR 0x100
#define LOG_INFO 0x200
#ifndef LOG_SECURITY
#define LOG_SECURITY 0x400
#endif
#define log(_level, fmt, arg...) do { \
int __attribute__((unused)) _querty = _level; \
printf("kernel: " fmt, ##arg); } while (0)
#endif /* _KERNEL */
/*
* Kernel locking support.
* FreeBSD uses mtx in dummynet.c and struct rwlock ip_fw2.c
*
* In linux we use spinlock_bh to implement both.
* For 'struct rwlock' we need an #ifdef to change it to spinlock_t
*/
#ifndef DEFINE_SPINLOCK /* this is for linux 2.4 */
#if defined(__APPLE__)
#define DEFINE_SPINLOCK(x) struct mtx x;
#else /* linux ? */
#define DEFINE_SPINLOCK(x) spinlock_t x // = SPIN_LOCK_UNLOCKED
#endif
#endif
/* 20111031
* redefine mutex in terms of threads.
*/
#undef _KERNEL
// #include <sys/types.h>
#include <pthread.h>
#ifdef NEED_KERNEL
#define _KERNEL
#endif
struct mtx {
pthread_mutex_t p0;
};
struct rwlock {
pthread_mutex_t p0;
};
struct rmlock {
pthread_mutex_t p0;
};
extern pthread_mutex_t dummynet_mtx_p;
extern pthread_mutex_t ipfw_dyn_mtx_p;
extern pthread_mutex_t pfil_global_lock_p;
#define mtx_assert(a, b)
/*
* the first argument to mtx_init is often a static variable,
* so use (void)m to prevent a compiler warning
*/
#define mtx_init(m, a,b,c) do { \
(void)m; pthread_mutex_init(&((m)->p0), NULL); } while (0)
#define MTX_SYSINIT(a, m, c, d) // pthread_mutex_init(m##_p, NULL)
#define mtx_lock(m) pthread_mutex_lock(m.p0)
#define mtx_unlock(m) pthread_mutex_unlock(m.p0)
#define mtx_destroy(m) pthread_mutex_destroy(m.p0)
#if 1
//------------------
#if 1 // used for IPFW_UH
#define rw_assert(a, b)
#define rw_destroy(_l)
#define rw_init(_l, msg) // XXX mtx_init((_l), 0, 0, 0)
#define rw_rlock(_l) mtx_lock(_l)
#define rw_runlock(_l) mtx_unlock(_l)
#define rw_wlock(_l) mtx_lock(_l)
#define rw_wunlock(_l) mtx_unlock(_l)
#define rw_init_flags(_l, s, v)
#endif // XXX not used anymore
#define rm_init(_l, msg) // mtx_init(...)
#define rm_rlock(_l, _t) ((void)_t, mtx_lock(_l))
#define rm_runlock(_l, _t) mtx_unlock(_l)
#define rm_wlock(_l) mtx_lock(_l)
#define rm_wunlock(_l) mtx_unlock(_l)
#define rm_destroy(_l) // XXX
#define rm_assert(_l, _w) // XXX
#endif // locking on linux ?
/* end of locking support */
/*
* Reference to an ipfw rule that can be carried outside critical sections.
* A rule is identified by rulenum:rule_id which is ordered.
* In version chain_id the rule can be found in slot 'slot', so
* we don't need a lookup if chain_id == chain->id.
*
* On exit from the firewall this structure refers to the rule after
* the matching one (slot points to the new rule; rulenum:rule_id-1
* is the matching rule), and additional info (e.g. info often contains
* the insn argument or tablearg in the low 16 bits, in host format).
* On entry, the structure is valid if slot>0, and refers to the starting
* rules. 'info' contains the reason for reinject, e.g. divert port,
* divert direction, and so on.
*/
struct ipfw_rule_ref {
uint32_t slot; /* slot for matching rule */
uint32_t rulenum; /* matching rule number */
uint32_t rule_id; /* matching rule id */
uint32_t chain_id; /* ruleset id */
uint32_t info; /* see below */
};
/* ISO C restricts enumerator values to range of 'int'
* so we need IN to have a smaller value
*/
enum {
IPFW_INFO_MASK = 0x0000ffff,
IPFW_INFO_OUT = 0x00000000, /* outgoing, just for convenience */
IPFW_INFO_IN = 0x00800000, /* incoming, overloads dir */
IPFW_ONEPASS = 0x40000000, /* One-pass, do not reinject */
IPFW_IS_MASK = 0x30000000, /* which source ? */
IPFW_IS_DIVERT = 0x20000000,
IPFW_IS_DUMMYNET =0x10000000,
IPFW_IS_PIPE = 0x08000000, /* pipe=1, queue = 0 */
};
/* in netinet/in.h */
#define in_nullhost(x) ((x).s_addr == INADDR_ANY)
/* ip_dummynet.c */
#ifndef __FreeBSD_version
#define __FreeBSD_version 500035
#endif
/* define some macro for ip_dummynet */
struct malloc_type {
};
#define MALLOC_DEFINE(type, shortdesc, longdesc) \
struct malloc_type type[1]; void *md_dummy_ ## type = type
#define CTASSERT(x)
/*
* gettimeofday would be in sys/time.h but it is not
* visible if _KERNEL is defined
*/
//int gettimeofday(struct timeval *, struct timezone *);
extern int hz;
extern long tick; /* exists in 2.4 but not in 2.6 */
extern int bootverbose;
extern struct timeval boottime;
/* time_uptime is a FreeBSD variable increased each second */
extern time_t time_uptime;
extern int max_linkhdr;
extern int ip_defttl;
extern u_long in_ifaddrhmask; /* mask for hash table */
extern struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */
/*-------------------------------------------------*/
/* define, includes and functions missing in linux */
/* include and define */
#include <arpa/inet.h> /* inet_ntoa */
struct mbuf;
// XXX #define M_MCAST 0x04 /* send/received as link-level multicast */
/* used by ip_dummynet.c */
void reinject_drop(struct mbuf* m);
#include <sys/socket.h> /* for ETHERTYPE_IP */
#ifdef _KERNEL
#define IF_NAMESIZE 16
#ifndef IFNAMSIZ
#define IFNAMSIZ IF_NAMESIZE
#endif
//#include <net/if.h> /* IFNAMESIZ */
#endif
/*
* some network structure can be defined in the bsd way
* by using the _FAVOR_BSD definition. This is not true
* for icmp structure.
* XXX struct icmp contains bsd names in
* /usr/include/netinet/ip_icmp.h
*/
/* missing definition */
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_ACK 0x10
/* 20131101 IPTOS from ip.h */
/*
* Definitions for DiffServ Codepoints as per RFC2474
*/
#define IPTOS_DSCP_CS0 0x00
#define IPTOS_DSCP_CS1 0x20
#define IPTOS_DSCP_AF11 0x28
#define IPTOS_DSCP_AF12 0x30
#define IPTOS_DSCP_AF13 0x38
#define IPTOS_DSCP_CS2 0x40
#define IPTOS_DSCP_AF21 0x48
#define IPTOS_DSCP_AF22 0x50
#define IPTOS_DSCP_AF23 0x58
#define IPTOS_DSCP_CS3 0x60
#define IPTOS_DSCP_AF31 0x68
#define IPTOS_DSCP_AF32 0x70
#define IPTOS_DSCP_AF33 0x78
#define IPTOS_DSCP_CS4 0x80
#define IPTOS_DSCP_AF41 0x88
#define IPTOS_DSCP_AF42 0x90
#define IPTOS_DSCP_AF43 0x98
#define IPTOS_DSCP_CS5 0xa0
#define IPTOS_DSCP_EF 0xb8
#define IPTOS_DSCP_CS6 0xc0
#define IPTOS_DSCP_CS7 0xe0
/*
* ECN (Explicit Congestion Notification) codepoints in RFC3168 mapped to the
* lower 2 bits of the TOS field.
*/
#define IPTOS_ECN_NOTECT 0x00 /* not-ECT */
#define IPTOS_ECN_ECT1 0x01 /* ECN-capable transport (1) */
#define IPTOS_ECN_ECT0 0x02 /* ECN-capable transport (0) */
#define IPTOS_ECN_CE 0x03 /* congestion experienced */
#define IPTOS_ECN_MASK 0x03 /* ECN field mask */
/*------------------------- */
#define RTF_CLONING 0x100 /* generate new routes on use */
#define IPPROTO_OSPFIGP 89 /* OSPFIGP */
#define IPPROTO_CARP 112 /* CARP */
#define CARP_VERSION 2
#define CARP_ADVERTISEMENT 0x01
#define PRIV_NETINET_IPFW 491 /* Administer IPFW firewall. */
#define IP_FORWARDING 0x1 /* most of ip header exists */
#define NETISR_IP 2 /* same as AF_INET */
#define PRIV_NETINET_DUMMYNET 494 /* Administer DUMMYNET. */
extern int securelevel;
#define if_xname name
#define if_snd XXX
// XXX we could use this to point to the incoming peer
struct ifnet {
char if_xname[IFNAMSIZ]; /* external name (name + unit) */
uint32_t if_index; // IP_FW_3
};
struct ifaltq {
void *ifq_head;
};
int ffs(int); // XXX where
int fls(int); // XXX where
struct ip;
/* machine/in_cksum.h */
int in_cksum(struct mbuf *m, int len);
#ifndef __FreeBSD__
u_short in_cksum_hdr(struct ip *);
#endif
#define CTR3(a, ...)
#define uma_zone_set_max(a, b) // XXX
/*
* ifnet->if_snd is used in ip_dummynet.c to take the transmission
* clock.
*/
#if defined( __linux__)
#define if_xname name
#define if_snd XXX
struct route_in6 {
};
#elif defined( _WIN32 )
/* used in ip_dummynet.c */
struct ifnet {
char if_xname[IFNAMSIZ]; /* external name (name + unit) */
// struct ifaltq if_snd; /* output queue (includes altq) */
};
struct net_device {
char if_xname[IFNAMSIZ]; /* external name (name + unit) */
};
#elif defined(__APPLE__)
typedef u_int32_t tcp_cc;
#ifndef s6_addr32 // XXX
#define s6_addr32 __u6_addr.__u6_addr32
#endif
#include <netinet/tcp.h>
struct route_in6 {
};
struct icmphdr {
u_char icmp_type; /* type of message, see below */
u_char icmp_code; /* type sub code */
u_short icmp_cksum; /* ones complement cksum of struct */
};
#define IPPROTO_SCTP 132 /* SCTP */
/* defined in linux/sctp.h with no bsd definition */
struct sctphdr {
uint16_t src_port; /* source port */
uint16_t dest_port; /* destination port */
uint32_t v_tag; /* verification tag of packet */
uint32_t checksum; /* Adler32 C-Sum */
/* chunks follow... */
};
struct carp_header {
#if BYTE_ORDER == LITTLE_ENDIAN
u_int8_t carp_type:4,
carp_version:4;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t carp_version:4,
carp_type:4;
#endif
};
struct pim {
int dummy; /* windows compiler does not like empty definition */
};
#endif
/* involves mbufs */
//int in_cksum(struct mbuf *m, int len);
#define divert_cookie(mtag) 0
#define divert_info(mtag) 0
#define pf_find_mtag(a) NULL
#define pf_get_mtag(a) NULL
#if !defined(_WIN32) && !defined(AF_LINK)
#define AF_LINK AF_ASH /* ? our sys/socket.h */
#endif
/* search local the ip addresses, used for the "me" keyword */
#define INADDR_TO_IFP(ip, b) b = NULL
/* we don't pullup, either success or free and fail */
#define m_pullup(m, x) \
((m)->m_len >= x ? (m) : (FREE_PKT(m), NULL))
struct pf_mtag {
void *hdr; /* saved hdr pos in mbuf, for ECN */
sa_family_t af; /* for ECN */
u_int32_t qid; /* queue id */
};
/* missing kernel functions */
char *inet_ntoa(struct in_addr ina);
long random(void);
/*
* Return the risult of a/b
*
* this is used in linux kernel space,
* since the 64bit division needs to
* be done using a macro
*/
//int64_t div64(int64_t a, int64_t b);
/* from bsd sys/queue.h */
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
/*-------------------------------------------------*/
#define RT_NUMFIBS 1
extern u_int rt_numfibs;
/* involves kernel locking function */
#ifdef RTFREE
#undef RTFREE
#define RTFREE(a) fprintf(stderr, "RTFREE: commented out locks\n");
#endif
void getmicrouptime(struct timeval *tv);
/* from sys/netinet/ip_output.c */
struct ip_moptions;
struct route;
struct ip;
struct inpcb;
struct mbuf *ip_reass(struct mbuf *);
int ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
struct ip_moptions *imo, struct inpcb *inp);
/* from net/netisr.c -- fails on FreeBSD */
int netisr_dispatch(u_int proto, struct mbuf *m);
/* definition moved in missing.c */
int sooptcopyout(struct sockopt *sopt, const void *buf, size_t len);
int copyout(const void *kaddr, void *uaddr, size_t len);
int sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen);
/* defined in session.c */
int priv_check(struct thread *td, int priv);
/* struct ucred is in linux/socket.h and has pid, uid, gid.
* We need a 'bsd_ucred' to store also the extra info
*/
struct bsd_ucred {
uid_t uid;
gid_t gid;
uint32_t xid;
uint32_t nid;
};
#ifdef _KERNEL
#if 0 // XXX
int
cred_check(void *insn, int proto, struct ifnet *oif,
struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,
struct sk_buff *skb);
#endif
struct ucred;
int securelevel_ge(struct ucred *cr, int level);
/*
* stripped down version of the sysctl api
*/
struct sysctl_oid;
struct sysctl_req {
void *oldptr; /* store here the original value */
int oldlen;
void *newptr; /* NULL on reads */
int newlen;
};
#ifdef _WIN32
#define module_param_named(_name, _var, _ty, _perm)
#else /* !_WIN32 */
#endif /* !_WIN32 so maybe __linux__ */
#if 0 // XXX disable sysctl defined (__linux__) && !defined (EMULATE_SYSCTL)
#define SYSCTL_DECL(_1)
#define SYSCTL_OID(_1, _2, _3, _4, _5, _6, _7, _8)
#define SYSCTL_NODE(_1, _2, _3, _4, _5, _6)
#define _SYSCTL_BASE(_name, _var, _ty, _perm) \
module_param_named(_name, *(_var), _ty, \
( (_perm) == CTLFLAG_RD) ? 0444: 0644 )
#define SYSCTL_PROC(_base, _oid, _name, _mode, _var, _val, _desc, _a, _b)
#define SYSCTL_INT(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, int, _mode)
#define SYSCTL_LONG(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, long, _mode)
#define SYSCTL_ULONG(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, ulong, _mode)
#define SYSCTL_UINT(_base, _oid, _name, _mode, _var, _val, _desc) \
_SYSCTL_BASE(_name, _var, uint, _mode)
#define TUNABLE_INT(_name, _ptr)
#define SYSCTL_VNET_PROC SYSCTL_PROC
#define SYSCTL_VNET_INT SYSCTL_INT
#define SYSCTL_VNET_UINT SYSCTL_UINT
#endif
#define SYSCTL_HANDLER_ARGS \
struct sysctl_oid *oidp, void *arg1, int arg2, struct sysctl_req *req
typedef int (sysctl_h_fn_t)(SYSCTL_HANDLER_ARGS);
int sysctl_handle_int(SYSCTL_HANDLER_ARGS);
int sysctl_handle_long(SYSCTL_HANDLER_ARGS);
#ifdef EMULATE_SYSCTL /* mandatory here */
#define STRINGIFY(x) #x
#ifdef SYSCTL_NODE
#undef SYSCTL_NODE
#endif
#define SYSCTL_NODE(a,b,c,d,e,f) int a; (void)a
#define SYSCTL_DECL(a)
#define GST_HARD_LIMIT 100
/* In the module, GST is implemented as an array of
* sysctlentry, but while passing data to the userland
* pointers are useless, the buffer is actually made of:
* - sysctlhead (fixed size, containing lengths)
* - data (typically 32 bit)
* - name (zero-terminated and padded to mod4)
*/
struct sysctlentry {
struct sysctlhead head;
char* name;
void* data;
sysctl_h_fn_t *fn;
};
struct sysctltable {
int count; //number of valid tables
int totalsize; //total size of valid entries of al the valid tables
void* namebuffer; //a buffer for all chained names
struct sysctlentry entry[GST_HARD_LIMIT];
};
#ifdef SYSBEGIN
#undef SYSBEGIN
#endif
#define SYSBEGIN(x) void sysctl_addgroup_##x() {
#ifdef SYSEND
#undef SYSEND
#endif
#define SYSEND }
/* XXX remove duplication */
#define SYSCTL_INT(a,b,c,d,e,f,g) \
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
(d) | (SYSCTLTYPE_INT << 2), sizeof(*e), e, NULL)
#define SYSCTL_UINT(a,b,c,d,e,f,g) \
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
(d) | (SYSCTLTYPE_UINT << 2), sizeof(*e), e, NULL)
#define SYSCTL_LONG(a,b,c,d,e,f,g) \
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
(d) | (SYSCTLTYPE_LONG << 2), sizeof(*e), e, NULL)
#define SYSCTL_ULONG(a,b,c,d,e,f,g) \
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
(d) | (SYSCTLTYPE_ULONG << 2), sizeof(*e), e, NULL)
#define TUNABLE_INT(a,b)
#define SYSCTL_PROC(a,b,c,d,e,f,g,h,i) \
sysctl_pushback(STRINGIFY(a) "." STRINGIFY(c) + 1, \
(d), 4 /* XXX large */, (void *)(f /* arg2 */), g)
#define SYSCTL_VNET_PROC SYSCTL_PROC
#define SYSCTL_VNET_INT SYSCTL_INT
#define SYSCTL_VNET_UINT SYSCTL_UINT
void keinit_GST(void);
void keexit_GST(void);
int kesysctl_emu_set(void* p, int l);
int kesysctl_emu_get(struct sockopt* sopt);
void sysctl_pushback(char* name, int flags, int datalen, void* data, sysctl_h_fn_t *fn);
#endif /* EMULATE_SYSCTL */
struct ifnet;
void ether_demux(struct ifnet *ifp, struct mbuf *m);
int ether_output_frame(struct ifnet *ifp, struct mbuf *m);
void in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum);
void icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu);
#define in_localip(_x) (0)
#ifndef __FreeBSD__
struct rtentry;
#endif
void rtfree(struct rtentry *rt);
u_short in_cksum_skip(struct mbuf *m, int len, int skip);
#ifdef INP_LOCK_ASSERT
#undef INP_LOCK_ASSERT
#define INP_LOCK_ASSERT(a)
#endif
int jailed(struct ucred *cred);
/*
* Return 1 if an internet address is for a ``local'' host
* (one to which we have a connection). If subnetsarelocal
* is true, this includes other subnets of the local net.
* Otherwise, it includes only the directly-connected (sub)nets.
*/
int in_localaddr(struct in_addr in);
int fnmatch(const char *pattern, const char *string, int flags);
/* vnet wrappers, in vnet.h and ip_var.h */
//int ipfw_init(void);
//void ipfw_destroy(void);
#define MTAG_IPFW 1148380143 /* IPFW-tagged cookie */
#define MTAG_IPFW_RULE 1262273568 /* rule reference */
#define MTAG_IPFW_CALL 1308397630 /* call stack */
#ifdef __APPLE__
#define offsetof(type, field) __builtin_offsetof(type, field)
#endif
struct ip_fw_args;
extern int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);
#if 1 /* include vnet.h */
#define curvnet NULL
#define CURVNET_SET(_v)
#define CURVNET_RESTORE()
#define VNET_ASSERT(condition)
#define VNET_NAME(n) n
#define VNET_DECLARE(t, n) extern t n
#define VNET_DEFINE(t, n) t n
#define _VNET_PTR(b, n) &VNET_NAME(n)
/*
* Virtualized global variable accessor macros.
*/
#define VNET_VNET_PTR(vnet, n) (&(n))
#define VNET_VNET(vnet, n) (n)
#define VNET_PTR(n) (&(n))
#define VNET(n) (n)
#define IS_DEFAULT_VNET(x) (1) // always true
#endif
VNET_DECLARE(int, ip_defttl);
#define V_ip_defttl VNET(ip_defttl);
// int ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, struct inpcb *inp);
// XXX used in netmap_io.c
int ipfw_check_packet(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, struct inpcb *inp);
int ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, struct inpcb *inp);
/* hooks for divert */
extern void (*ip_divert_ptr)(struct mbuf *m, int incoming);
extern int (*ip_dn_ctl_ptr)(struct sockopt *);
typedef int ip_fw_ctl_t(struct sockopt *);
extern ip_fw_ctl_t *ip_fw_ctl_ptr;
/* netgraph prototypes */
typedef int ng_ipfw_input_t(struct mbuf **, int, struct ip_fw_args *, int);
extern ng_ipfw_input_t *ng_ipfw_input_p;
/* For kernel ipfw_ether and ipfw_bridge. */
struct ip_fw_args;
#define V_ip_fw_ctl_ptr VNET(ip_fw_ctl_ptr)
#define V_tcbinfo VNET(tcbinfo)
#define V_udbinfo VNET(udbinfo)
#endif /* _KERNEL */
// sys/eventhandler.h
#define EVENTHANDLER_DECLARE(a, b)
/* application specific */
struct sess;
typedef int (handler_t)(struct sess *sess, void *arg);
/*
* flags to control the callback
* WANT_READ select on read
* WANT_WRITE select on write
* WANT_RUN run unconditionally
* WANT_DELETE session is exiting
*/
enum flags_t {
WANT_READ=1, WANT_WRITE=2, WANT_RUN=4,
WANT_DELETE=0x8000
};
struct sess {
struct sess *next;
int fd;
handler_t *func;
void *arg;
enum flags_t flags;
void *private; /* pointer managed by the session code */
};
struct sess *
new_session(int fd, handler_t *func, void *arg, enum flags_t flags);
void netmap_add_port(const char *dev);
#endif /* !_MISSING_H_ */

View File

View File

View File

@ -0,0 +1,264 @@
/*-
* Copyright (c) 1998-2010 Luigi Rizzo, Universita` di Pisa
* Portions Copyright (c) 2000 Akamba Corp.
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: head/sys/netinet/ip_dummynet.h 266941 2014-06-01 07:28:24Z hiren $
*/
#ifndef _IP_DUMMYNET_H
#define _IP_DUMMYNET_H
/*
* Definition of the kernel-userland API for dummynet.
*
* Setsockopt() and getsockopt() pass a batch of objects, each
* of them starting with a "struct dn_id" which should fully identify
* the object and its relation with others in the sequence.
* The first object in each request should have
* type= DN_CMD_*, id = DN_API_VERSION.
* For other objects, type and subtype specify the object, len indicates
* the total length including the header, and 'id' identifies the specific
* object.
*
* Most objects are numbered with an identifier in the range 1..65535.
* DN_MAX_ID indicates the first value outside the range.
*/
#define DN_API_VERSION 12500000
#define DN_MAX_ID 0x10000
struct dn_id {
uint16_t len; /* total obj len including this header */
uint8_t type;
uint8_t subtype;
uint32_t id; /* generic id */
};
/*
* These values are in the type field of struct dn_id.
* To preserve the ABI, never rearrange the list or delete
* entries with the exception of DN_LAST
*/
enum {
DN_NONE = 0,
DN_LINK = 1,
DN_FS,
DN_SCH,
DN_SCH_I,
DN_QUEUE,
DN_DELAY_LINE,
DN_PROFILE,
DN_FLOW, /* struct dn_flow */
DN_TEXT, /* opaque text is the object */
DN_CMD_CONFIG = 0x80, /* objects follow */
DN_CMD_DELETE, /* subtype + list of entries */
DN_CMD_GET, /* subtype + list of entries */
DN_CMD_FLUSH,
/* for compatibility with FreeBSD 7.2/8 */
DN_COMPAT_PIPE,
DN_COMPAT_QUEUE,
DN_GET_COMPAT,
/* special commands for emulation of sysctl variables */
DN_SYSCTL_GET,
DN_SYSCTL_SET,
DN_LAST,
};
enum { /* subtype for schedulers, flowset and the like */
DN_SCHED_UNKNOWN = 0,
DN_SCHED_FIFO = 1,
DN_SCHED_WF2QP = 2,
/* others are in individual modules */
};
enum { /* user flags */
DN_HAVE_MASK = 0x0001, /* fs or sched has a mask */
DN_NOERROR = 0x0002, /* do not report errors */
DN_QHT_HASH = 0x0004, /* qht is a hash table */
DN_QSIZE_BYTES = 0x0008, /* queue size is in bytes */
DN_HAS_PROFILE = 0x0010, /* a link has a profile */
DN_IS_RED = 0x0020,
DN_IS_GENTLE_RED= 0x0040,
DN_IS_ECN = 0x0080,
DN_PIPE_CMD = 0x1000, /* pipe config... */
};
/*
* link template.
*/
struct dn_link {
struct dn_id oid;
/*
* Userland sets bw and delay in bits/s and milliseconds.
* The kernel converts this back and forth to bits/tick and ticks.
* XXX what about burst ?
*/
int32_t link_nr;
int bandwidth; /* bit/s or bits/tick. */
int delay; /* ms and ticks */
uint64_t burst; /* scaled. bits*Hz XXX */
};
/*
* A flowset, which is a template for flows. Contains parameters
* from the command line: id, target scheduler, queue sizes, plr,
* flow masks, buckets for the flow hash, and possibly scheduler-
* specific parameters (weight, quantum and so on).
*/
struct dn_fs {
struct dn_id oid;
uint32_t fs_nr; /* the flowset number */
uint32_t flags; /* userland flags */
int qsize; /* queue size in slots or bytes */
int32_t plr; /* PLR, pkt loss rate (2^31-1 means 100%) */
uint32_t buckets; /* buckets used for the queue hash table */
struct ipfw_flow_id flow_mask;
uint32_t sched_nr; /* the scheduler we attach to */
/* generic scheduler parameters. Leave them at -1 if unset.
* Now we use 0: weight, 1: lmax, 2: priority
*/
int par[4];
/* RED/GRED parameters.
* weight and probabilities are in the range 0..1 represented
* in fixed point arithmetic with SCALE_RED decimal bits.
*/
#define SCALE_RED 16
#define SCALE(x) ( (x) << SCALE_RED )
#define SCALE_VAL(x) ( (x) >> SCALE_RED )
#define SCALE_MUL(x,y) ( ( (x) * (y) ) >> SCALE_RED )
int w_q ; /* queue weight (scaled) */
int max_th ; /* maximum threshold for queue (scaled) */
int min_th ; /* minimum threshold for queue (scaled) */
int max_p ; /* maximum value for p_b (scaled) */
};
/*
* dn_flow collects flow_id and stats for queues and scheduler
* instances, and is used to pass these info to userland.
* oid.type/oid.subtype describe the object, oid.id is number
* of the parent object.
*/
struct dn_flow {
struct dn_id oid;
struct ipfw_flow_id fid;
uint64_t tot_pkts; /* statistics counters */
uint64_t tot_bytes;
uint32_t length; /* Queue length, in packets */
uint32_t len_bytes; /* Queue length, in bytes */
uint32_t drops;
};
/*
* Scheduler template, mostly indicating the name, number,
* sched_mask and buckets.
*/
struct dn_sch {
struct dn_id oid;
uint32_t sched_nr; /* N, scheduler number */
uint32_t buckets; /* number of buckets for the instances */
uint32_t flags; /* have_mask, ... */
char name[16]; /* null terminated */
/* mask to select the appropriate scheduler instance */
struct ipfw_flow_id sched_mask; /* M */
};
/* A delay profile is attached to a link.
* Note that a profile, as any other object, cannot be longer than 2^16
*/
#define ED_MAX_SAMPLES_NO 1024
struct dn_profile {
struct dn_id oid;
/* fields to simulate a delay profile */
#define ED_MAX_NAME_LEN 32
char name[ED_MAX_NAME_LEN];
int link_nr;
int loss_level;
int _bandwidth; // XXX use link bandwidth? unused ?
int samples_no; /* actual len of samples[] */
int samples[ED_MAX_SAMPLES_NO]; /* may be shorter */
};
/*
* Overall structure of dummynet
In dummynet, packets are selected with the firewall rules, and passed
to two different objects: PIPE or QUEUE (bad name).
A QUEUE defines a classifier, which groups packets into flows
according to a 'mask', puts them into independent queues (one
per flow) with configurable size and queue management policy,
and passes flows to a scheduler:
(flow_mask|sched_mask) sched_mask
+---------+ weight Wx +-------------+
| |->-[flow]-->--| |-+
-->--| QUEUE x | ... | | |
| |->-[flow]-->--| SCHEDuler N | |
+---------+ | | |
... | +--[LINK N]-->--
+---------+ weight Wy | | +--[LINK N]-->--
| |->-[flow]-->--| | |
-->--| QUEUE y | ... | | |
| |->-[flow]-->--| | |
+---------+ +-------------+ |
+-------------+
Many QUEUE objects can connect to the same scheduler, each
QUEUE object can have its own set of parameters.
In turn, the SCHEDuler 'forks' multiple instances according
to a 'sched_mask', each instance manages its own set of queues
and transmits on a private instance of a configurable LINK.
A PIPE is a simplified version of the above, where there
is no flow_mask, and each scheduler instance handles a single queue.
The following data structures (visible from userland) describe
the objects used by dummynet:
+ dn_link, contains the main configuration parameters related
to delay and bandwidth;
+ dn_profile describes a delay profile;
+ dn_flow describes the flow status (flow id, statistics)
+ dn_sch describes a scheduler
+ dn_fs describes a flowset (msk, weight, queue parameters)
*
*/
#endif /* _IP_DUMMYNET_H */

File diff suppressed because it is too large Load Diff

View File

View File

2013
lib/ipfw/tables.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,11 @@
noinst_LTLIBRARIES = libpgw.la
libpgw_la_SOURCES = \
pgw_ipfw.h \
pgw_event.h pgw_context.h pgw_sm.h \
pgw_gtp_path.h pgw_s5c_build.h pgw_s5c_handler.h \
pgw_fd_path.h pgw_gx_handler.h \
pgw_ipfw.c \
pgw_init.c pgw_event.c pgw_context.c pgw_sm.c \
pgw_gtp_path.c pgw_s5c_build.c pgw_s5c_handler.c \
pgw_fd_path.c pgw_gx_handler.c
@ -14,20 +16,23 @@ libpgw_la_DEPENDENCIES = \
$(top_srcdir)/lib/core/src/libcore.la \
$(top_srcdir)/lib/fd/gx/libfdgx.la \
$(top_srcdir)/lib/fd/libfd.la \
$(top_srcdir)/lib/gtp/libgtp.la
$(top_srcdir)/lib/gtp/libgtp.la \
$(top_srcdir)/lib/ipfw/libipfw.la
libpgw_la_LIBADD = \
$(top_srcdir)/lib/core/src/libcore.la \
$(top_srcdir)/lib/fd/gx/libfdgx.la \
$(top_srcdir)/lib/fd/libfd.la \
$(top_srcdir)/lib/gtp/libgtp.la
$(top_srcdir)/lib/gtp/libgtp.la \
$(top_srcdir)/lib/ipfw/libipfw.la
AM_CPPFLAGS = \
-I$(top_srcdir)/lib/core/include \
-I$(top_srcdir)/lib/base \
-I$(top_srcdir)/lib/fd/gx \
-I$(top_srcdir)/lib/fd \
-I$(top_srcdir)/lib/gtp
-I$(top_srcdir)/lib/gtp \
-I$(top_srcdir)/lib/ipfw
AM_CFLAGS = \
-Wall -Werror

View File

@ -19,6 +19,7 @@ index_declare(pgw_sess_pool, pgw_sess_t, MAX_POOL_OF_SESS);
index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER);
pool_declare(pgw_ip_pool_pool, pgw_ip_pool_t, MAX_POOL_OF_SESS);
pool_declare(pgw_pf_pool, pgw_pf_t, MAX_POOL_OF_PF);
static int context_initiaized = 0;
@ -36,6 +37,7 @@ status_t pgw_context_init()
index_init(&pgw_bearer_pool, MAX_POOL_OF_BEARER);
pool_init(&pgw_ip_pool_pool, MAX_POOL_OF_SESS);
pool_init(&pgw_pf_pool, MAX_POOL_OF_PF);
self.sess_hash = hash_make();
@ -73,6 +75,7 @@ status_t pgw_context_final()
index_size(&pgw_ip_pool_pool) - pool_avail(&pgw_ip_pool_pool),
index_size(&pgw_ip_pool_pool));
pool_final(&pgw_pf_pool);
pool_final(&pgw_ip_pool_pool);
index_final(&pgw_bearer_pool);
@ -652,6 +655,8 @@ pgw_bearer_t* pgw_bearer_add(pgw_sess_t *sess)
index_alloc(&pgw_bearer_pool, &bearer);
d_assert(bearer, return NULL, "Bearer context allocation failed");
list_init(&bearer->pf_list);
bearer->pgw_s5u_teid = bearer->index;
bearer->pgw_s5u_addr = pgw_self()->s5u_addr;
@ -666,6 +671,8 @@ status_t pgw_bearer_remove(pgw_bearer_t *bearer)
d_assert(bearer, return CORE_ERROR, "Null param");
d_assert(bearer->sess, return CORE_ERROR, "Null param");
pgw_pf_remove_all(bearer);
list_remove(&bearer->sess->bearer_list, bearer);
index_free(&pgw_bearer_pool, bearer);
@ -824,6 +831,80 @@ pgw_bearer_t* pgw_bearer_find_by_packet(pkbuf_t *pkt)
return NULL;
}
pgw_pf_t *pgw_pf_add(pgw_bearer_t *bearer, c_uint32_t precedence)
{
pgw_pf_t *pf = NULL;
d_assert(bearer, return NULL, "Null param");
pool_alloc_node(&pgw_pf_pool, &pf);
d_assert(pf, return NULL, "Null param");
pf->identifier = NEXT_ID(bearer->pf_identifier, 1, 15);
list_append(&bearer->pf_list, pf);
pf->bearer = bearer;
return pf;
}
status_t pgw_pf_remove(pgw_pf_t *pf)
{
d_assert(pf, return CORE_ERROR, "Null param");
d_assert(pf->bearer, return CORE_ERROR, "Null param");
list_remove(&pf->bearer->pf_list, pf);
pool_free_node(&pgw_pf_pool, pf);
return CORE_OK;
}
status_t pgw_pf_remove_all(pgw_bearer_t *bearer)
{
pgw_pf_t *pf = NULL, *next_pf = NULL;
d_assert(bearer, return CORE_ERROR, "Null param");
pf = pgw_pf_first(bearer);
while (pf)
{
next_pf = pgw_pf_next(pf);
pgw_pf_remove(pf);
pf = next_pf;
}
return CORE_OK;
}
pgw_pf_t* pgw_pf_find_by_id(pgw_bearer_t *bearer, c_uint8_t id)
{
pgw_pf_t *pf = NULL;
pf = pgw_pf_first(bearer);
while (pf)
{
if (pf->identifier == id)
return pf;
pf = pgw_pf_next(pf);
}
return CORE_OK;
}
pgw_pf_t* pgw_pf_first(pgw_bearer_t *bearer)
{
return list_first(&bearer->pf_list);
}
pgw_pf_t* pgw_pf_next(pgw_pf_t *pf)
{
return list_next(pf);
}
status_t pgw_ip_pool_generate()
{
int i, j, k;

View File

@ -114,11 +114,52 @@ typedef struct _pgw_bearer_t {
c_uint32_t sgw_s5u_teid;
c_uint32_t sgw_s5u_addr;
/* QoS Infomration */
qos_t qos;
/* Packet Filter Identifier Generator(1~15) */
c_uint8_t pf_identifier;
/* Packet Filter List */
list_t pf_list;
pgw_sess_t *sess;
} pgw_bearer_t;
typedef struct _pgw_rule_t {
c_uint8_t proto;
struct {
struct {
c_uint32_t addr;
c_uint32_t mask;
} local;
struct {
c_uint32_t addr;
c_uint32_t mask;
} remote;
} ipv4;
struct {
struct {
c_uint16_t low;
c_uint32_t high;
} local;
struct {
c_uint16_t low;
c_uint32_t high;
} remote;
} port;
} pgw_rule_t;
typedef struct _pgw_pf_t {
lnode_t node;
ED3(c_uint8_t spare:2;,
c_uint8_t direction:2;,
c_uint8_t identifier:4;)
pgw_rule_t rule;
pgw_bearer_t *bearer;
} pgw_pf_t;
CORE_DECLARE(status_t) pgw_context_init(void);
CORE_DECLARE(status_t) pgw_context_final(void);
CORE_DECLARE(pgw_context_t*) pgw_self(void);
@ -166,6 +207,15 @@ CORE_DECLARE(pgw_bearer_t*) pgw_bearer_next(pgw_bearer_t *bearer);
CORE_DECLARE(pgw_bearer_t*) pgw_bearer_find_by_packet(pkbuf_t *pkt);
CORE_DECLARE(pgw_pf_t*) pgw_pf_add(
pgw_bearer_t *bearer, c_uint32_t precedence);
CORE_DECLARE(status_t ) pgw_pf_remove(pgw_pf_t *pf);
CORE_DECLARE(status_t ) pgw_pf_remove_all(pgw_bearer_t *bearer);
CORE_DECLARE(pgw_pf_t*) pgw_pf_find_by_id(
pgw_bearer_t *pgw_bearer, c_uint8_t id);
CORE_DECLARE(pgw_pf_t*) pgw_pf_first(pgw_bearer_t *bearer);
CORE_DECLARE(pgw_pf_t*) pgw_pf_next(pgw_pf_t *pf);
CORE_DECLARE(status_t ) pgw_ip_pool_generate();
CORE_DECLARE(pgw_ip_pool_t*) pgw_ip_pool_alloc();
CORE_DECLARE(status_t ) pgw_ip_pool_free(pgw_ip_pool_t *ip_pool);

View File

@ -6,46 +6,7 @@
#include "gx_message.h"
#include "pgw_gtp_path.h"
#include "pgw_s5c_build.h"
void pgw_gx_handle_create_bearer_request(pgw_sess_t *sess, pcc_rule_t *pcc_rule)
{
status_t rv;
gtp_xact_t *xact = NULL;
gtp_header_t h;
pkbuf_t *pkbuf = NULL;
pgw_bearer_t *bearer = NULL;
d_assert(sess, return, "Null param");
d_assert(pcc_rule, return, "Null param");
bearer = pgw_bearer_find_by_qci_arp(sess,
pcc_rule->qos.qci,
pcc_rule->qos.arp.priority_level,
pcc_rule->qos.arp.pre_emption_capability,
pcc_rule->qos.arp.pre_emption_vulnerability);
if (bearer)
{
return;
}
bearer = pgw_bearer_add(sess);
d_assert(bearer, return, "Null param");
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(qos_t));
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(qos_t));
memset(&h, 0, sizeof(gtp_header_t));
h.type = GTP_CREATE_BEARER_REQUEST_TYPE;
h.teid = sess->sgw_s5c_teid;
rv = pgw_s5c_build_create_bearer_request(&pkbuf, h.type, bearer);
d_assert(rv == CORE_OK, return, "S11 build error");
xact = gtp_xact_local_create(sess->sgw, &h, pkbuf);
d_assert(xact, return, "Null param");
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
}
#include "pgw_ipfw.h"
void pgw_gx_handle_cca_initial_request(
gtp_xact_t *xact, pgw_sess_t *sess,
@ -54,15 +15,18 @@ void pgw_gx_handle_cca_initial_request(
status_t rv;
gtp_header_t h;
pkbuf_t *pkbuf = NULL;
int i = 0;
int i = 0, j = 0;
pgw_bearer_t *bearer = NULL;
d_assert(xact, return, "Null param");
d_assert(sess, return, "Null param");
d_assert(cca_message, return, "Null param");
d_assert(req, return, "Null param");
/* Setup GTP Node between PGW and SGW */
CONNECT_SGW_GTP_NODE(sess, xact);
/* Send Create Session Request with Creating Default Bearer */
memset(&h, 0, sizeof(gtp_header_t));
h.type = GTP_CREATE_SESSION_RESPONSE_TYPE;
h.teid = sess->sgw_s5c_teid;
@ -77,9 +41,67 @@ void pgw_gx_handle_cca_initial_request(
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
/* Find Dedicated Bearer */
for (i = 0; i < cca_message->num_of_pcc_rule; i++)
{
pgw_gx_handle_create_bearer_request(sess, &cca_message->pcc_rule[i]);
pcc_rule_t *pcc_rule = &cca_message->pcc_rule[i];
bearer = pgw_bearer_find_by_qci_arp(sess,
pcc_rule->qos.qci,
pcc_rule->qos.arp.priority_level,
pcc_rule->qos.arp.pre_emption_capability,
pcc_rule->qos.arp.pre_emption_vulnerability);
if (!bearer)
bearer = pgw_bearer_add(sess);
d_assert(bearer, return, "Null param");
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(qos_t));
for (j = 0; j < pcc_rule->num_of_flow; j++)
{
flow_t *flow = &pcc_rule->flow[j];
pgw_rule_t rule;
pgw_pf_t *pf = NULL;
d_assert(flow, return, "Null param");
d_assert(flow->description, return, "Null param");
rv = pgw_compile_packet_filter(&rule, flow->description);
d_assert(rv == CORE_OK, return, "Failed to compile packet filter");
pf = pgw_pf_add(bearer, pcc_rule->precedence);
d_assert(pf, return, "Null param");
memcpy(&pf->rule, &rule, sizeof(pgw_rule_t));
pf->direction = flow->direction;
}
}
/* Skip Default Bearer */
bearer = pgw_default_bearer_in_sess(sess);
d_assert(bearer, return, "Null param");
/* Send Create Bearer Request for Dedicated Bearer */
bearer = pgw_bearer_next(bearer);
while(bearer)
{
gtp_xact_t *xact = NULL;
gtp_header_t h;
pkbuf_t *pkbuf = NULL;
memset(&h, 0, sizeof(gtp_header_t));
h.type = GTP_CREATE_BEARER_REQUEST_TYPE;
h.teid = sess->sgw_s5c_teid;
rv = pgw_s5c_build_create_bearer_request(&pkbuf, h.type, bearer);
d_assert(rv == CORE_OK, return, "S11 build error");
xact = gtp_xact_local_create(sess->sgw, &h, pkbuf);
d_assert(xact, return, "Null param");
rv = gtp_xact_commit(xact);
d_assert(rv == CORE_OK, return, "xact_commit error");
bearer = pgw_bearer_next(bearer);
}
}

118
src/pgw/pgw_ipfw.c Normal file
View File

@ -0,0 +1,118 @@
#define TRACE_MODULE _pgw_ipfw
#include "pgw_ipfw.h"
#include "ipfw2.h"
#include "objs/include_e/netinet/ip_fw.h"
#define MAX_NUM_OF_TOKEN 32
#define MAX_NUM_OF_RULE_BUFFER 1024
void compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, void *tstate);
status_t pgw_compile_packet_filter(pgw_rule_t *pgw_rule, c_int8_t *description)
{
pgw_rule_t zero_rule;
char *token, *dir;
char *saveptr;
int i = 2;
char *av[MAX_NUM_OF_TOKEN];
uint32_t rulebuf[MAX_NUM_OF_RULE_BUFFER];
int rbufsize;
struct ip_fw_rule *rule = (struct ip_fw_rule *)rulebuf;
int l;
ipfw_insn *cmd;
d_assert(pgw_rule, return CORE_ERROR, "Null param");
d_assert(description, return CORE_ERROR, "Null param");
rbufsize = sizeof(rulebuf);
memset(rulebuf, 0, rbufsize);
av[0] = NULL;
/* ACTION */
token = strtok_r(description, " ", &saveptr);
if (strcmp(token, "permit") != 0)
{
d_error("Not begins with reserved keyword : 'permit'");
return CORE_ERROR;
}
av[1] = token;
/* Save DIRECTION */
dir = token = strtok_r(NULL, " ", &saveptr);
if (strcmp(token, "out") != 0)
{
d_error("Not begins with reserved keyword : 'permit out'");
return CORE_ERROR;
}
/* ADDR */
token = strtok_r(NULL, " ", &saveptr);
while(token != NULL)
{
av[i++] = token;
token = strtok_r(NULL, " ", &saveptr);
}
/* Add DIRECTION */
av[i++] = dir;
av[i] = NULL;
compile_rule(av, (uint32_t *)rule, &rbufsize, NULL);
memset(pgw_rule, 0, sizeof(pgw_rule_t));
for (l = rule->act_ofs, cmd = rule->cmd;
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd))
{
switch(cmd->opcode)
{
case O_PROTO:
pgw_rule->proto = cmd->arg1;
break;
case O_IP_SRC:
case O_IP_SRC_MASK:
{
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
pgw_rule->ipv4.local.addr = a[0];
pgw_rule->ipv4.local.mask = a[1];
break;
}
case O_IP_DST:
case O_IP_DST_MASK:
{
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
pgw_rule->ipv4.remote.addr = a[0];
pgw_rule->ipv4.remote.mask = a[1];
break;
}
case O_IP_SRCPORT:
{
uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
pgw_rule->port.local.low = p[0];
pgw_rule->port.local.high = p[1];
break;
}
case O_IP_DSTPORT:
{
uint16_t *p = ((ipfw_insn_u16 *)cmd)->ports;
pgw_rule->port.remote.low = p[0];
pgw_rule->port.remote.high = p[1];
break;
}
}
}
memset(&zero_rule, 0, sizeof(pgw_rule_t));
if (memcmp(pgw_rule, &zero_rule, sizeof(pgw_rule_t)) == 0)
{
d_error("Cannot find Flow-Description");
return CORE_ERROR;
}
return CORE_OK;
}

11
src/pgw/pgw_ipfw.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __PGW_IPFW_H__
#define __PGW_IPFW_H__
#include "core_debug.h"
#include "pgw_context.h"
CORE_DECLARE(status_t) pgw_compile_packet_filter(
pgw_rule_t *pf, c_int8_t *description);
#endif /* __PGW_IPFW_H__ */

View File

@ -170,6 +170,10 @@ status_t pgw_s5c_build_create_bearer_request(
gtp_f_teid_t pgw_s5u_teid;
gtp_bearer_qos_t bearer_qos;
char bearer_qos_buf[GTP_BEARER_QOS_LEN];
gtp_tft_t tft;
int i, j, len;
char tft_buf[GTP_MAX_TRAFFIC_FLOW_TEMPLATE];
pgw_pf_t *pf = NULL;
d_assert(bearer, return CORE_ERROR, "Null param");
sess = bearer->sess;
@ -215,6 +219,95 @@ status_t pgw_s5c_build_create_bearer_request(
gtp_build_bearer_qos(&req->bearer_contexts.bearer_level_qos,
&bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN);
/* Bearer TFT */
memset(&tft, 0, sizeof(tft));
tft.code = GTP_TFT_CODE_CREATE_NEW_TFT;
i = 0;
pf = pgw_pf_first(bearer);
while(pf)
{
tft.pf[i].direction = pf->direction;
tft.pf[i].identifier = pf->identifier - 1;
tft.pf[i].precedence = i+1;
j = 0, len = 0;
if (pf->rule.proto)
{
tft.pf[i].component[j].type =
GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE;
tft.pf[i].component[j].proto = pf->rule.proto;
j++; len += 2;
}
if (pf->rule.ipv4.local.addr)
{
tft.pf[i].component[j].type =
GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
tft.pf[i].component[j].ipv4.addr = pf->rule.ipv4.local.addr;
tft.pf[i].component[j].ipv4.mask = pf->rule.ipv4.local.mask;
j++; len += 9;
}
if (pf->rule.ipv4.remote.addr)
{
tft.pf[i].component[j].type =
GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
tft.pf[i].component[j].ipv4.addr = pf->rule.ipv4.remote.addr;
tft.pf[i].component[j].ipv4.mask = pf->rule.ipv4.remote.mask;
j++; len += 9;
}
if (pf->rule.port.local.low)
{
if (pf->rule.port.local.low == pf->rule.port.local.high)
{
tft.pf[i].component[j].type =
GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
tft.pf[i].component[j].port.low = pf->rule.port.local.low;
j++; len += 3;
}
else
{
tft.pf[i].component[j].type =
GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
tft.pf[i].component[j].port.low = pf->rule.port.local.low;
tft.pf[i].component[j].port.high = pf->rule.port.local.high;
j++; len += 5;
}
}
if (pf->rule.port.remote.low)
{
if (pf->rule.port.remote.low == pf->rule.port.remote.high)
{
tft.pf[i].component[j].type =
GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
tft.pf[i].component[j].port.low = pf->rule.port.remote.low;
j++; len += 3;
}
else
{
tft.pf[i].component[j].type =
GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
tft.pf[i].component[j].port.low = pf->rule.port.remote.low;
tft.pf[i].component[j].port.high = pf->rule.port.remote.high;
j++; len += 5;
}
}
tft.pf[i].num_of_component = j;
tft.pf[i].length = len;
i++;
pf = pgw_pf_next(pf);
}
tft.num_of_packet_filter = i;
req->bearer_contexts.tft.presence = 1;
gtp_build_tft(&req->bearer_contexts.tft,
&tft, tft_buf, GTP_MAX_TRAFFIC_FLOW_TEMPLATE);
gtp_message.h.type = type;
rv = gtp_build_msg(pkbuf, &gtp_message);
d_assert(rv == CORE_OK, return CORE_ERROR, "gtp build failed");