kern/82724: Add setnexthop and defaultroute features to ipfw2

Ari Suutari ari at suutari.iki.fi
Tue Jun 28 09:00:32 GMT 2005


>Number:         82724
>Category:       kern
>Synopsis:       Add setnexthop and defaultroute features to ipfw2
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jun 28 09:00:31 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Ari Suutari
>Release:        FreeBSD 5.4-RELEASE-p2 i386
>Organization:
>Environment:
System: FreeBSD mato.suutari.iki.fi 5.4-RELEASE-p2 FreeBSD 5.4-RELEASE-p2 #18: Tue Jun 21 14:10:18 EEST 2005 ari at mato.suutari.iki.fi:/usr/obj/usr/src/sys/MATO i386


>Description:

	Although ipfw2 supports policy routing via 'ipfw forward' 
	statement, it is not easy to use as it could be. Because
	rule searching terminates when ipfw forward is processed,
	using policy routing affects the ipfw ruleset a lot, which
	makes it difficult to use with large rulesets.

	Attached patch adds new 'ipfw setnexthop' feature, which
	is basically same as ipfw forward, but search continues
	at next rule. Now one can tweak routing for packets without
	affecting accept/deny status done by other rules.

	Patch also adds new keyword 'defaultroute', which matches
	packets going out via default route (ie. no specific route
	is found in routing table). With this, it is easy
	for example to policy route all generic web-surfing by
	saying just:

	ipfw add setnexthop g2.g2.g2.g2 ip from any to any out defaultroute
	
	(well, in reality NAT might be needed also by this setup,
	but that is possible also).

	Patch has been viewed already by Luigi Rizzo, his comments were:

        "ok.  Seen the patch, looks good."

	The discussion has been on freebsd-net mailing list under
	subject "Policy routing idea", starting at 21.6.2005.


>How-To-Repeat:
	Not applicable, this is a new feature.
>Fix:

Following patches are agains 5.4-RELEASE.
They are also available at http://www.suutari.iki.fi/freebsd

Index: ipfw.8
===================================================================
RCS file: /mnt/src/sbin/ipfw/ipfw.8,v
retrieving revision 1.150.2.6
diff -c -r1.150.2.6 ipfw.8
*** ipfw.8	2 Mar 2005 19:50:11 -0000	1.150.2.6
--- ipfw.8	23 Jun 2005 07:36:16 -0000
***************
*** 674,679 ****
--- 674,683 ----
  Discard packets that match this rule, and if the
  packet is a TCP packet, try to send a TCP reset (RST) notice.
  The search terminates.
+ .It Cm setnexthop Ar ipaddr Ns Op , Ns Ar port
+ Works like 
+ .Cm forward
+ but search continues at next rule.
  .It Cm skipto Ar number
  Skip all subsequent rules numbered less than
  .Ar number .
***************
*** 920,925 ****
--- 924,931 ----
  .It Cm bridged
  Alias for
  .Cm layer2 .
+ .It Cm defaultroute
+ Matches IP packets whose destination IP is routed via default route.
  .It Cm dst-ip Ar ip-address
  Matches IP packets whose destination IP is one of the address(es)
  specified as argument.
Index: ipfw2.c
===================================================================
RCS file: /mnt/src/sbin/ipfw/ipfw2.c,v
retrieving revision 1.54.2.4
diff -c -r1.54.2.4 ipfw2.c
*** ipfw2.c	25 Jan 2005 07:23:34 -0000	1.54.2.4
--- ipfw2.c	23 Jun 2005 09:34:17 -0000
***************
*** 253,258 ****
--- 253,260 ----
  	TOK_DROPTAIL,
  	TOK_PROTO,
  	TOK_WEIGHT,
+ 	TOK_SETNEXTHOP,
+ 	TOK_DEFAULTROUTE
  };
  
  struct _s_x dummynet_params[] = {
***************
*** 299,304 ****
--- 301,307 ----
  	{ "unreach",		TOK_UNREACH },
  	{ "check-state",	TOK_CHECKSTATE },
  	{ "//",			TOK_COMMENT },
+ 	{ "setnexthop",		TOK_SETNEXTHOP },
  	{ NULL, 0 }	/* terminator */
  };
  
***************
*** 350,355 ****
--- 353,359 ----
  	{ "versrcreach",	TOK_VERSRCREACH },
  	{ "antispoof",		TOK_ANTISPOOF },
  	{ "ipsec",		TOK_IPSEC },
+ 	{ "defaultroute",	TOK_DEFAULTROUTE },
  	{ "//",			TOK_COMMENT },
  
  	{ "not",		TOK_NOT },		/* pseudo option */
***************
*** 1029,1034 ****
--- 1033,1048 ----
  		    }
  			break;
  
+ 		case O_SETNEXTHOP:
+ 		    {
+ 			ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
+ 
+ 			printf("setnexthop %s", inet_ntoa(s->sa.sin_addr));
+ 			if (s->sa.sin_port)
+ 				printf(",%d", s->sa.sin_port);
+ 		    }
+ 			break;
+ 
  		case O_LOG: /* O_LOG is printed last */
  			logptr = (ipfw_insn_log *)cmd;
  			break;
***************
*** 1308,1313 ****
--- 1322,1331 ----
  				printf(" ipsec");
  				break;
  
+ 			case O_DEFAULTROUTE:
+ 				printf(" defaultroute");
+ 				break;
+ 
  			case O_NOP:
  				comment = (char *)(cmd + 1);
  				break;
***************
*** 2902,2914 ****
  		ac--; av++;
  		break;
  
! 	case TOK_FORWARD: {
  		ipfw_insn_sa *p = (ipfw_insn_sa *)action;
  		char *s, *end;
  
  		NEED1("missing forward address[:port]");
  
! 		action->opcode = O_FORWARD_IP;
  		action->len = F_INSN_SIZE(ipfw_insn_sa);
  
  		p->sa.sin_len = sizeof(struct sockaddr_in);
--- 2920,2933 ----
  		ac--; av++;
  		break;
  
! 	case TOK_FORWARD:
! 	case TOK_SETNEXTHOP: {
  		ipfw_insn_sa *p = (ipfw_insn_sa *)action;
  		char *s, *end;
  
  		NEED1("missing forward address[:port]");
  
! 		action->opcode = i == TOK_FORWARD ? O_FORWARD_IP : O_SETNEXTHOP;
  		action->len = F_INSN_SIZE(ipfw_insn_sa);
  
  		p->sa.sin_len = sizeof(struct sockaddr_in);
***************
*** 3490,3495 ****
--- 3509,3518 ----
  			fill_cmd(cmd, O_IPSEC, 0, 0);
  			break;
  
+ 		case TOK_DEFAULTROUTE:
+ 			fill_cmd(cmd, O_DEFAULTROUTE, 0, 0);
+ 			break;
+ 
  		case TOK_COMMENT:
  			fill_comment(cmd, ac, av);
  			av += ac;




Index: ip_fw.h
===================================================================
RCS file: /mnt/src/sys/netinet/ip_fw.h,v
retrieving revision 1.89.2.3
diff -c -r1.89.2.3 ip_fw.h
*** ip_fw.h	31 Jan 2005 23:26:35 -0000	1.89.2.3
--- ip_fw.h	23 Jun 2005 06:36:43 -0000
***************
*** 134,139 ****
--- 134,141 ----
  	O_IP_DST_LOOKUP,	/* arg1=table number, u32=value	*/
  	O_ANTISPOOF,		/* none				*/
  	O_JAIL,			/* u32 = id			*/
+ 	O_SETNEXTHOP,		/* nexthop sockaddr		*/
+ 	O_DEFAULTROUTE,		/* none				*/
  
  	O_LAST_OPCODE		/* not an opcode!		*/
  };
Index: ip_fw2.c
===================================================================
RCS file: /mnt/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.70.2.10
diff -c -r1.70.2.10 ip_fw2.c
*** ip_fw2.c	6 Feb 2005 16:16:20 -0000	1.70.2.10
--- ip_fw2.c	23 Jun 2005 09:53:05 -0000
***************
*** 636,646 ****
  			snprintf(SNPARGS(action2, 0), "Queue %d",
  				cmd->arg1);
  			break;
! 		case O_FORWARD_IP: {
  			ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd;
  			int len;
  
! 			len = snprintf(SNPARGS(action2, 0), "Forward to %s",
  				inet_ntoa(sa->sa.sin_addr));
  			if (sa->sa.sin_port)
  				snprintf(SNPARGS(action2, len), ":%d",
--- 636,649 ----
  			snprintf(SNPARGS(action2, 0), "Queue %d",
  				cmd->arg1);
  			break;
! 		case O_FORWARD_IP:
! 		case O_SETNEXTHOP: {
  			ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd;
  			int len;
  
! 			len = snprintf(SNPARGS(action2, 0), "%s to %s",
! 				(cmd->opcode == O_FORWARD_IP ?
! 					"Forward" : "SetNextHop"),
  				inet_ntoa(sa->sa.sin_addr));
  			if (sa->sa.sin_port)
  				snprintf(SNPARGS(action2, len), ":%d",
***************
*** 2294,2299 ****
--- 2297,2307 ----
  				/* otherwise no match */
  				break;
  
+ 			case O_DEFAULTROUTE:
+ 				match = (hlen > 0 && 
+ 				     !verify_path(dst_ip, NULL));
+ 				break;
+ 
  			/*
  			 * The second set of opcodes represents 'actions',
  			 * i.e. the terminal part of a rule once the packet
***************
*** 2450,2462 ****
  				goto done;
  
  			case O_FORWARD_IP:
  				if (args->eh)	/* not valid on layer2 pkts */
  					break;
  				if (!q || dyn_dir == MATCH_FORWARD)
  					args->next_hop =
  					    &((ipfw_insn_sa *)cmd)->sa;
! 				retval = 0;
! 				goto done;
  
  			default:
  				panic("-- unknown opcode %d\n", cmd->opcode);
--- 2458,2481 ----
  				goto done;
  
  			case O_FORWARD_IP:
+ 			case O_SETNEXTHOP:
  				if (args->eh)	/* not valid on layer2 pkts */
  					break;
  				if (!q || dyn_dir == MATCH_FORWARD)
  					args->next_hop =
  					    &((ipfw_insn_sa *)cmd)->sa;
!             
! 				if (cmd->opcode == O_FORWARD_IP) {
! 					retval = 0;
! 					goto done;
! 				}
! 				else {
! 					f->pcnt++;	/* update stats */
! 					f->bcnt += pktlen;
! 					f->timestamp = time_second;
! 
! 					goto next_rule;
! 				}
  
  			default:
  				panic("-- unknown opcode %d\n", cmd->opcode);
***************
*** 2923,2928 ****
--- 2942,2948 ----
  		case O_VERSRCREACH:
  		case O_ANTISPOOF:
  		case O_IPSEC:
+ 		case O_DEFAULTROUTE:
  			if (cmdlen != F_INSN_SIZE(ipfw_insn))
  				goto bad_size;
  			break;
***************
*** 3019,3024 ****
--- 3039,3045 ----
  			goto check_action;
  
  		case O_FORWARD_IP:
+ 		case O_SETNEXTHOP:
  #ifdef	IPFIREWALL_FORWARD
  			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
  				goto bad_size;
***************
*** 3026,3032 ****
  #else
  			return EINVAL;
  #endif
- 
  		case O_DIVERT:
  		case O_TEE:
  #ifndef	IPDIVERT
--- 3047,3052 ----
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list