diff -ru src/sbin/ipfw/ipfw.8 /usr/src/sbin/ipfw/ipfw.8 --- src/sbin/ipfw/ipfw.8 Sat Jul 29 12:24:12 2006 +++ /usr/src/sbin/ipfw/ipfw.8 Thu Aug 24 10:42:19 2006 @@ -823,6 +823,14 @@ and .Cm ngtee actions. +.It Cm iptos Ar code +Changes +.Cm tos +field of an IPv4 packet. +.It Cm dscp Ar code +Changes +.Cm dscp +field of an IPv4 packet. .El .Ss RULE BODY The body of a rule contains zero or more patterns (such as @@ -1273,6 +1281,55 @@ The absence of a particular type may be denoted with a .Ql \&! . +.It Cm dscp Ar code +Matches IPv4 packets whose +.Cm dscp +field contains +.Ar code . +The supported values are: +.Pp +.Cm CS0 +.Pq Dv 000000 , +.Cm CS1 +.Pq Dv 001000 , +.Cm CS2 +.Pq Dv 010000 , +.Cm CS3 +.Pq Dv 011000 , +.Cm CS4 +.Pq Dv 100000 , +.Cm CS5 +.Pq Dv 101000 , +.Cm CS6 +.Pq Dv 110000 , +.Cm CS7 +.Pq Dv 111000 , +.Cm AF11 +.Pq Dv 001010 , +.Cm AF12 +.Pq Dv 001100 , +.Cm AF13 +.Pq Dv 001110 , +.Cm AF21 +.Pq Dv 010010 , +.Cm AF22 +.Pq Dv 010100 , +.Cm AF23 +.Pq Dv 010110 , +.Cm AF31 +.Pq Dv 011010 , +.Cm AF32 +.Pq Dv 011100 , +.Cm AF33 +.Pq Dv 011110 , +.Cm AF41 +.Pq Dv 100010 , +.Cm AF42 +.Pq Dv 100100 , +.Cm AF43 +.Pq Dv 100110 , +.Cm EF +.Pq Dv 101110 . .It Cm ipttl Ar ttl-list Matches IPv4 packets whose time to live is included in .Ar ttl-list , diff -ru src/sbin/ipfw/ipfw2.c /usr/src/sbin/ipfw/ipfw2.c --- src/sbin/ipfw/ipfw2.c Mon Aug 7 23:32:57 2006 +++ /usr/src/sbin/ipfw/ipfw2.c Thu Aug 24 10:14:10 2006 @@ -133,6 +133,33 @@ int x; }; +static struct _s_x f_ipdscp[] = { + /* DSCP */ + { "AF11", 40 }, + { "AF12", 48 }, + { "AF13", 56 }, + { "AF21", 72 }, + { "AF22", 80 }, + { "AF23", 88 }, + { "AF31", 104 }, + { "AF32", 112 }, + { "AF33", 120 }, + { "AF41", 136 }, + { "AF42", 144 }, + { "AF43", 152 }, + { "EF", 184 }, + /* COS flags */ + { "CS0", 0 }, + { "CS1", 32 }, + { "CS2", 64 }, + { "CS3", 96 }, + { "CS4", 128 }, + { "CS5", 160 }, + { "CS6", 192 }, + { "CS7", 224 }, + { NULL, 0 } +}; + static struct _s_x f_tcpflags[] = { { "syn", TH_SYN }, { "fin", TH_FIN }, @@ -274,6 +301,7 @@ TOK_IPID, TOK_IPPRECEDENCE, TOK_IPTOS, + TOK_IPDSCP, TOK_IPTTL, TOK_IPVER, TOK_ESTAB, @@ -309,6 +337,8 @@ TOK_DROPTAIL, TOK_PROTO, TOK_WEIGHT, + TOK_SETIPTOS, + TOK_SETDSCP, TOK_IPV6, TOK_FLOWID, @@ -374,6 +404,8 @@ { "unreach6", TOK_UNREACH6 }, { "unreach", TOK_UNREACH }, { "check-state", TOK_CHECKSTATE }, + { "iptos", TOK_SETIPTOS }, + { "dscp", TOK_SETDSCP }, { "//", TOK_COMMENT }, { NULL, 0 } /* terminator */ }; @@ -411,6 +443,7 @@ { "ipid", TOK_IPID }, { "ipprecedence", TOK_IPPRECEDENCE }, { "iptos", TOK_IPTOS }, + { "dscp", TOK_IPDSCP }, { "ipttl", TOK_IPTTL }, { "ipversion", TOK_IPVER }, { "ipver", TOK_IPVER }, @@ -1550,6 +1583,12 @@ printf(",%d", s->sa.sin_port); } break; + case O_SET_IPTOS: + printf("iptos %s", match_value(f_iptos, cmd->arg1)); + break; + case O_SET_DSCP: + printf("dscp %s", match_value(f_ipdscp, cmd->arg1)); + break; case O_LOG: /* O_LOG is printed last */ logptr = (ipfw_insn_log *)cmd; @@ -1855,6 +1894,10 @@ print_flags("iptos", cmd, f_iptos); break; + case O_IPDSCP: + printf(" dscp %s", match_value(f_ipdscp, cmd->arg1)); + break; + case O_ICMPTYPE: print_icmptypes((ipfw_insn_u32 *)cmd); break; @@ -2631,7 +2674,7 @@ "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" "ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n" " skipto N | {divert|tee} PORT | forward ADDR |\n" -" pipe N | queue N\n" +" pipe N | queue N | iptos CODE | dscp CODE\n" "PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n" "ADDR: [ MAC dst src ether_type ] \n" " [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" @@ -2642,8 +2685,8 @@ "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" "OPTION_LIST: OPTION [OPTION_LIST]\n" "OPTION: bridged | diverted | diverted-loopback | diverted-output |\n" -" {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" -" {dst-port|src-port} LIST |\n" +" dscp CODE | {dst-ip|src-ip} IPADDR |\n" +" {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR | {dst-port|src-port} LIST |\n" " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" @@ -3960,6 +4003,18 @@ case TOK_COUNT: action->opcode = O_COUNT; break; + + case TOK_SETIPTOS: + NEED1("need iptos arg\n"); + fill_flags(action, O_SET_IPTOS, f_iptos, *av); + ac--; av++; + break; + + case TOK_SETDSCP: + NEED1("need dscp arg\n"); + fill_flags(action, O_SET_DSCP, f_ipdscp, *av); + ac--; av++; + break; case TOK_QUEUE: action->len = F_INSN_SIZE(ipfw_insn_pipe); @@ -4446,6 +4501,12 @@ case TOK_IPTOS: NEED1("missing argument for iptos"); fill_flags(cmd, O_IPTOS, f_iptos, *av); + ac--; av++; + break; + + case TOK_IPDSCP: + NEED1("missing argument for dscp"); + fill_flags(cmd, O_IPDSCP, f_ipdscp, *av); ac--; av++; break; diff -ru src/sys/netinet/ip_fw.h /usr/src/sys/netinet/ip_fw.h --- src/sys/netinet/ip_fw.h Sat Jul 29 12:24:12 2006 +++ /usr/src/sys/netinet/ip_fw.h Wed Aug 23 17:22:43 2006 @@ -160,6 +160,10 @@ O_TAG, /* arg1=tag number */ O_TAGGED, /* arg1=tag number */ + O_SET_IPTOS, /* arg1 = iptos */ + O_SET_DSCP, /* arg1 = dscp */ + O_IPDSCP, /* arg1 = DSCP */ + O_LAST_OPCODE /* not an opcode! */ }; @@ -563,6 +567,21 @@ typedef int ip_fw_chk_t(struct ip_fw_args *args); extern ip_fw_chk_t *ip_fw_chk_ptr; #define IPFW_LOADED (ip_fw_chk_ptr != NULL) + +#define ADJUST_CHECKSUM(acc, cksum) \ + do { \ + acc += cksum; \ + if (acc < 0) { \ + acc = -acc; \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) ~acc; \ + } else { \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) acc; \ + } \ + } while (0) #endif /* _KERNEL */ #endif /* _IPFW2_H */ diff -ru src/sys/netinet/ip_fw2.c /usr/src/sys/netinet/ip_fw2.c --- src/sys/netinet/ip_fw2.c Sat Jul 29 12:24:12 2006 +++ /usr/src/sys/netinet/ip_fw2.c Thu Aug 24 10:43:17 2006 @@ -145,6 +145,21 @@ NET_ASSERT_GIANT(); \ } while (0) +static __inline int +twowords(void *p) +{ + uint8_t *c = p; + +#if BYTE_ORDER == LITTLE_ENDIAN + uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0]; + uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2]; +#else + uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1]; + uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3]; +#endif + return (s1 + s2); +} + static __inline void IPFW_RLOCK(struct ip_fw_chain *chain) { @@ -2427,6 +2442,7 @@ for (; f; f = f->next) { ipfw_insn *cmd; uint32_t tablearg = 0; + int accumulate; int l, cmdlen, skip_or; /* skip rest of OR block */ again: @@ -2734,6 +2750,11 @@ flags_match(cmd, mtod(m, struct ip *)->ip_tos)); break; + case O_IPDSCP: + match = (is_ipv4 && + (cmd->arg1 == (mtod(m, struct ip *)->ip_tos & 0xfc)) ); + break; + case O_TCPDATALEN: if (proto == IPPROTO_TCP && offset == 0) { struct tcphdr *tcp; @@ -3052,6 +3073,28 @@ } match = 1; break; + + case O_SET_IPTOS: + accumulate = twowords(&ip->ip_tos); + /* for tos, we have to change whole byte, + and for dscp bits 0-5 only */ + ip->ip_tos = cmd->arg1; + accumulate -= twowords(&ip->ip_tos); + ADJUST_CHECKSUM(accumulate, ip->ip_sum); + f->pcnt++; /* update stats */ + f->bcnt += pktlen; + f->timestamp = time_second; + goto next_rule; + + case O_SET_DSCP: + accumulate = twowords(&ip->ip_tos); + ip->ip_tos = ip->ip_tos | cmd->arg1; + accumulate -= twowords(&ip->ip_tos); + ADJUST_CHECKSUM(accumulate, ip->ip_sum); + f->pcnt++; /* update stats */ + f->bcnt += pktlen; + f->timestamp = time_second; + goto next_rule; case O_PROBE_STATE: case O_CHECK_STATE: @@ -3655,6 +3698,7 @@ case O_DIVERTED: case O_IPOPT: case O_IPTOS: + case O_IPDSCP: case O_IPPRECEDENCE: case O_IPVER: case O_TCPWIN: @@ -3675,6 +3719,11 @@ case O_TAG: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; + break; + + case O_SET_DSCP: + case O_SET_IPTOS: + have_action = 1; break; case O_UID: