[1023] in linux-net channel archive
Patches for firewall to alter priority of frames
daemon@ATHENA.MIT.EDU (Al Longyear)
Fri Sep 1 04:10:36 1995
From: Al Longyear <longyear@sii.com>
To: linux-net@vger.rutgers.edu
Date: Thu, 31 Aug 1995 12:26:59 -0700 (PDT)
Reply-To: longyear@netcom.com
A couple of weeks back there was a discussion on the PPP list regarding the
need to implement a re-prioritization of the frames through a serial link
from multiple clients.
I spent some time and determined a set of patches to the 1.3.17 kernel
which was the current kernel at the time.
I would like to contribute these patches to the next 1.3 kernel but do not
know just to whom I should send it. I hope that the proper people have
subscribed to the linux-net group and would get a copy of this message.
These patches are relative to the 1.3.21 kernel which I obtained a day or
so ago and the net-tools package on sunacm.swan.ac.uk. I do not have the
code for ipfwadm to make the change to that program.
The addition is to include a new field, "priority". This is an "and" and
"xor" mask pair which is applied to the IP_TOS octect as the rule is accepted.
The idea is to alter the priority of the frame as it passes through the
firewall from brain-dead clients on the local side of the firewall.
There is litte which can be done to brain-dead servers on the other side
of the serial link short of delaying the ack frames to them.
I did not choose to apply the rules against all frames which are generated
by the local system since the local system should generate the proper IP_TOS
priority in the first place and that there is no firewall call for the
socket layer. I do not wish to add additional overhead in this procedure
on the chance that you are using a broken client or server on the local
Linux system.
At any rate, these are the patches to the kernel.
--- linux/include/linux/ip_fw.h.orig Thu Aug 31 08:15:26 1995
+++ linux/include/linux/ip_fw.h Thu Aug 31 12:08:22 1995
@@ -57,10 +57,27 @@
/* src ports; max of 10 ports in all; */
/* count of 0 means match all ports) */
#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */
unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */
+ unsigned short fw_priority; /* Revised packet priority */
+};
+
+struct ip_fw_old
+{
+ struct ip_fw *fw_next; /* Next firewall on chain */
+ struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
+ struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
+ struct in_addr fw_via; /* IP address of interface "via" */
+ unsigned short fw_flg; /* Flags word */
+ unsigned short fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */
+ /* in ports array (dst ports follow */
+ /* src ports; max of 10 ports in all; */
+ /* count of 0 means match all ports) */
+#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */
+ unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
+ unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */
};
/*
* Values for "flags" field .
*/
--- linux/net/ipv4/ip_fw.c.orig Tue Aug 29 09:46:26 1995
+++ linux/net/ipv4/ip_fw.c Thu Aug 31 12:08:23 1995
@@ -187,11 +187,11 @@
struct icmphdr *icmp=(struct icmphdr *)((unsigned long *)ip+ip->ihl);
__u32 src, dst;
__u16 src_port=0, dst_port=0, icmp_type=0;
unsigned short f_prt=0, prt;
char notcpsyn=1, notcpack=1, frag1, match;
- unsigned short f_flag;
+ int answer, priority;
/*
* If the chain is empty follow policy. The BSD one
* accepts anything giving you a time window while
* flushing and rebuilding the tables.
@@ -430,28 +430,40 @@
}
if (opt != 1)
break;
} /* Loop */
- if(opt == 1)
- return 0;
+ answer = 0;
/*
* We rely on policy defined in the rejecting entry or, if no match
* was found, we rely on the general policy variable for this type
* of firewall.
*/
- if(f!=NULL) /* A match was found */
- f_flag=f->fw_flg;
- else
- f_flag=policy;
- if(f_flag&IP_FW_F_ACCEPT)
- return ((f_flag&IP_FW_F_MASQ)?2:1);
- if(f_flag&IP_FW_F_ICMPRPL)
- return -1;
- return 0;
+ if(f!=NULL) {
+ policy=f->fw_flg;
+ priority=f->fw_priority;
+ } else
+ priority=0xFF00;
+
+ if(opt != 1) {
+ if(policy&IP_FW_F_ACCEPT)
+ answer=(policy&IP_FW_F_MASQ)?2:1;
+ else
+ if(policy&IP_FW_F_ICMPRPL)
+ answer = -1;
+ }
+
+ if (answer == 0) { /* Adjust priority and recompute checksum */
+ __u8 old_tos = ip->tos;
+ ip->tos = (old_tos & (priority>>8)) ^ priority;
+ if (ip->tos != old_tos)
+ ip_send_check(ip);
+ }
+
+ return answer;
}
#ifdef CONFIG_IP_MASQUERADE
static void masq_expire(unsigned long data)
@@ -899,11 +911,11 @@
restore_flags(flags);
}
/* Volatiles to keep some of the compiler versions amused */
-static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl)
+static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len)
{
struct ip_fw *ftmp;
struct ip_fw *chtmp=NULL;
struct ip_fw *volatile chtmp_prev=NULL;
unsigned long flags;
@@ -923,12 +935,15 @@
printk("ip_fw_ctl: malloc said no\n");
#endif
return( ENOMEM );
}
- memcpy(ftmp, frwl, sizeof( struct ip_fw ) );
+ memcpy(ftmp, frwl, len);
+ if (len == sizeof (struct ip_fw_old))
+ ftmp->fw_priority = 0xFF00; /* and_mask, xor_mask */
+ ftmp->fw_priority = (ftmp->fw_priority & 0xFFFC) | 0x0300;
ftmp->fw_pcnt=0L;
ftmp->fw_bcnt=0L;
ftmp->fw_next = NULL;
@@ -1163,11 +1178,11 @@
#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
{
- if ( len != sizeof(struct ip_fw) )
+ if ( len != sizeof(struct ip_fw) && len != sizeof(struct ip_fw_old))
{
#ifdef DEBUG_CONFIG_IP_FIREWALL
printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw));
#endif
return(NULL);
@@ -1247,11 +1262,11 @@
return (EINVAL);
switch (stage)
{
case IP_ACCT_ADD:
- return( add_to_chain(&ip_acct_chain,frwl));
+ return( add_to_chain(&ip_acct_chain,frwl,len));
case IP_ACCT_DEL:
return( del_from_chain(&ip_acct_chain,frwl));
default:
/*
* Should be panic but... (Why ??? - AC)
@@ -1366,13 +1381,13 @@
return (EINVAL);
switch (stage)
{
case IP_FW_ADD_BLK:
- return(add_to_chain(&ip_fw_blk_chain,frwl));
+ return(add_to_chain(&ip_fw_blk_chain,frwl,len));
case IP_FW_ADD_FWD:
- return(add_to_chain(&ip_fw_fwd_chain,frwl));
+ return(add_to_chain(&ip_fw_fwd_chain,frwl,len));
case IP_FW_DEL_BLK:
return(del_from_chain(&ip_fw_blk_chain,frwl));
case IP_FW_DEL_FWD:
return(del_from_chain(&ip_fw_fwd_chain,frwl));
default:
@@ -1442,10 +1457,11 @@
ntohl(i->fw_via.s_addr),i->fw_flg);
len+=sprintf(buffer+len,"%u %u %-9lu %-9lu",
i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
for (p = 0; p < IP_FW_MAX_PORTS; p++)
len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
+ len+=sprintf(buffer+len, " M%04X", i->fw_priority);
buffer[len++]='\n';
buffer[len]='\0';
pos=begin+len;
if(pos<offset)
{
These are the patches to the ipfw program in the nettools package.
--- ipfw.c.ORIG Wed Aug 9 08:21:45 1995
+++ ipfw.c Thu Aug 10 05:51:35 1995
@@ -48,10 +48,14 @@
#include <string.h>
#include <errno.h>
#include <ctype.h>
#define IPVERSION 4
+#define FW_PRIORITY_HIGH 0x1F40
+#define FW_PRIORITY_MEDIUM 0x1F20
+#define FW_PRIORITY_LOW 0x1F00
+
#ifdef IP_FW_F_MASQ
#define DO_MASQUERADE
#endif
#include "config.h"
#include "net-locale.h"
@@ -291,11 +295,43 @@
printf("}\n");
}
}
else
{
- if (setsockopt(fd, proto, cmd, data, datalen) < 0)
+ if (setsockopt(fd, proto, cmd, data, datalen) >= 0)
+ {
+ errno = 0;
+ }
+
+ if (errno == 0 || errno == ok_errno)
+ {
+ return (errno);
+ }
+
+ if (errno == ENOPROTOOPT)
+ {
+ fprintf (stderr, "ipfw: setsockopt(%s): IP Firewall support not in kernel", cmdname);
+ NLS_CATCLOSE(catfd)
+ exit(1);
+ }
+
+ if (errno == EINVAL && datalen > sizeof (struct ip_fw_old))
+ {
+ datalen=sizeof(struct ip_fw_old);
+ if (((struct ip_fw *)data)->fw_priority != 0xFF00)
+ {
+ fprintf (stderr, "Kernel does not support "
+ "re-prioritizing. UPGRADE!\n");
+ }
+
+ if (setsockopt(fd, proto, cmd, data, datalen) >= 0)
+ {
+ errno = 0;
+ }
+ }
+
+ if (errno != 0)
{
char msg[128];
if (errno == ok_errno)
{
@@ -810,10 +846,13 @@
{
int protocol, accept_firewall, src_range, dst_range;
struct ip_fw firewall;
char *proto_name;
+ memset (&firewall, '\0', sizeof (firewall));
+ firewall.fw_priority = 0xFF00;
+
printf(NLS_CATGETS(catfd, ipfwSet, ipfw_add, "add %s "), nls_ipf_names[kind]);
show_parms(argv);
printf("\n");
if (kind != IPF_ACCOUNTING && kind != IPF_MASQUERADE)
@@ -877,18 +916,37 @@
NLS_CATCLOSE(catfd)
exit(1);
}
argv++;
}
+
+ if (argv && strcmp (*argv, "high") == 0)
+ {
+ firewall.fw_priority = FW_PRIORITY_HIGH;
+ ++argv;
+ }
+ else
+ if (argv && strcmp (*argv, "medium") == 0)
+ {
+ firewall.fw_priority = FW_PRIORITY_MEDIUM;
+ ++argv;
+ }
+ else
+ if (argv && strcmp (*argv, "low") == 0)
+ {
+ firewall.fw_priority = FW_PRIORITY_LOW;
+ ++argv;
+ }
if (*argv == NULL)
{
fprintf(stderr, NLS_CATGETS(catfd, ipfwSet, ipfw_missing_from2,
"ipfw: missing \"from\" keyword\n"));
NLS_CATCLOSE(catfd)
exit(1);
}
+
if (strcmp(*argv, "from") == 0)
{
argv++;
get_ipaddr(*argv++, &firewall.fw_src, &firewall.fw_smsk, add_usage, kind);
if (protocol == IP_FW_F_TCP || protocol == IP_FW_F_UDP)
@@ -997,10 +1055,13 @@
{
int protocol, accept_firewall, src_range, dst_range;
struct ip_fw firewall;
char *proto_name;
+ memset (&firewall, '\0', sizeof (firewall));
+ firewall.fw_priority = 0xFF00;
+
printf(NLS_CATGETS(catfd, ipfwSet, ipfw_delete, "delete %s "), nls_ipf_names[kind]);
show_parms(argv);
printf("\n");
if (kind != IPF_ACCOUNTING && kind != IPF_MASQUERADE)
@@ -1190,10 +1251,11 @@
unsigned long sa, da, sm, dm, iface;
unsigned int nsp, ndp;
unsigned long npkt, nbyt;
unsigned int fw_pts[10];
int fw_flg;
+ int priority;
} fw_rec;
#define MIN(a,b) ((a)<(b)? (a): (b))
#define SRC(x) ((x)->sa & (x)->sm)
#define DST(x) ((x)->da & (x)->dm)
@@ -1261,13 +1323,14 @@
void list_file(char *path, int acct)
{
FILE *f = fopen(path, "r");
int nrecs = 8;
int nused = 0;
+ int count;
fw_rec *recs = (void *) malloc(sizeof(fw_rec) * nrecs);
fw_rec *rec;
- char buf[256];
+ char buf[256], *cptr;
struct servent *sptr;
if (f == NULL)
{
perror(path);
@@ -1283,17 +1346,35 @@
recs = (void *) realloc(recs, sizeof(fw_rec) * nrecs);
}
rec = &recs[nused++];
rec->acct = acct;
- sscanf(buf,
- "%lX/%lX->%lX/%lX %lX %X %u %u %lu %lu %u %u %u %u %u %u %u %u %u %u",
+ memset (rec, 0, sizeof (rec));
+ rec->priority = 0xFF00;
+ count = sscanf(buf,
+ "%lX/%lX->%lX/%lX "
+ "%lX %X %u %u %lu %lu %u %u %u %u %u %u %u %u %u %u",
&rec->sa, &rec->sm, &rec->da, &rec->dm, &rec->iface,
- &rec->fw_flg, &rec->nsp, &rec->ndp, &rec->npkt, &rec->nbyt,
- &rec->fw_pts[0], &rec->fw_pts[1], &rec->fw_pts[2], &rec->fw_pts[3],
- &rec->fw_pts[4], &rec->fw_pts[5], &rec->fw_pts[6], &rec->fw_pts[7],
- &rec->fw_pts[8], &rec->fw_pts[9]);
+ &rec->fw_flg, &rec->nsp, &rec->ndp, &rec->npkt,
+ &rec->nbyt,
+ &rec->fw_pts[0], &rec->fw_pts[1], &rec->fw_pts[2],
+ &rec->fw_pts[3], &rec->fw_pts[4], &rec->fw_pts[5],
+ &rec->fw_pts[6], &rec->fw_pts[7], &rec->fw_pts[8],
+ &rec->fw_pts[9]);
+/*
+ * Fetch the optional parameters on the record
+ */
+ cptr = buf + count;
+ cptr = strtok (cptr, " ");
+ while (cptr != NULL)
+ {
+ if (*cptr == 'M')
+ {
+ rec->priority = strtoul (++cptr, NULL, 16);
+ }
+ cptr = strtok (NULL, " ");
+ }
}
fclose(f);
qsort(recs, nused, sizeof(fw_rec), list_order);
@@ -1419,10 +1500,20 @@
++pp;
sep = ",";
}
}
}
+
+ if (rec->priority == FW_PRIORITY_HIGH)
+ printf (" >high");
+ else
+ if (rec->priority == FW_PRIORITY_MEDIUM)
+ printf (" >medium");
+ else
+ if (rec->priority == FW_PRIORITY_LOW)
+ printf (" >low");
+
printf("\n");
}
endservent();
}
--- man/en_US.88591/ipfw.8.orig Thu Aug 10 19:23:36 1995
+++ man/en_US.88591/ipfw.8 Thu Aug 10 19:37:49 1995
@@ -43,11 +43,11 @@
zero[accounting] - clear chain counters(for now accounting only).
The <chain-entry pattern> build like this:
For forwarding/blocking chains:
deny <proto/addr pattern>
- accept <proto/addr pattern>
+ accept [<priority>] <proto/addr pattern>
The <proto/addr pattern> is:
all|icmp from <src addr/mask> to <dst addr/mask>
tcp|udp from <src addr/mask> [ports] to <dst addr/mask> [ports]
@@ -55,27 +55,51 @@
<INET IP addr | domain name> [/mask bits | :mask pattern]
[ports]:
[ port,port....|port:port] where name of service can be
used instead of port numeric value.
+ The <priority> field is optional.It may be one of the following
+ \fIlow\fR,\fImedium\fR,\fIhigh\fR.\fImedium\fR is the normal value.
+
When entry added to chain and -v option used,entry added with
PRN flag set.
The <packet pattern> build exactly like <chain-entry pattern>.
To l[ist] command may be passed:
f[orwarding]|b[locking]|a[ccounting] to list specific chain or none
to list all of them.Option -v causes output format to change so that
-packet/bytes counters printed.Standart output format fully suitable
+packet/bytes counters printed.Standard output format fully suitable
to be used as <chain-entry pattern>.
To f[lush] command may be passed:
f[irewall]|a[ccounting] to remove all entries from forwarding/blocking
chains or from accounting chain.No arguments removes all chain entries.
To zero[accounting] command no arguments needed,and all counters of
- accounting chain zeroed.
+accounting chain zeroed.
+
+.Sh RE-PRIORITIZING FRAMES
+
+ The forwarding firewall may be used to alter the priority of IP
+frames as they flow through the system. To accomplish this, the
+priority is specified with the command. Such frames should be marked
+as \fIallow\fR for this to have any effect.
+ The purpose of this logic is to address the situation where you have
+an internal network comprised of clients or servers which do not set
+the proper priority for a frame \fIand\fR you have a slow link to the
+next higher network which is forming your firewall. The un-specified
+frames will arrive at the firewall with the same priority and this
+means that frames for data transfers and interactive operations can
+not be properly prioritized in competing for the critical resource of
+your slow link.
+ The priority option permits you to specify frames for either a
+specific subnet of your internal network or frames for a specific
+service as having the indicated priority of high, medium (the
+default), or low. The high priority should be used for interactive
+frames while the low priority is reserved for data transfers of a
+sizable quantity.
.Sh EXAMPLES
This command add entry which denies all tcp packets from
hacker.evil.org to telnet port of wolf.tambov.su from being
@@ -89,10 +113,13 @@
.Sh BUGS
WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!
This programm can put your computer in rather unusable state.
First time try using it from console and do *NOT* do anything
you don't understand.
+ Remember that the loopback address may be blocked as well. Many
+programs expect that they will be able to reach the local computer
+using the loopback device.
Remember that "ipfw flush" can solve all the problemms.
Also take in your mind that "ipfw policy deny" combined with
some wrong chain entry(possible the only entry which designed
to deny some external packets) can close your computer from
outer world for good.
--
Al Longyear longyear@netcom.com longyear@sii.com