iplang_y.y revision 369245
1/*	$FreeBSD: stable/11/contrib/ipfilter/iplang/iplang_y.y 369245 2021-02-09 13:47:46Z git2svn $	*/
2
3%{
4/*
5 * Copyright (C) 2012 by Darren Reed.
6 *
7 * See the IPFILTER.LICENCE file for details on licencing.
8 *
9 * Id: iplang_y.y,v 2.9.2.4 2006/03/17 12:11:29 darrenr Exp $
10 * $FreeBSD: stable/11/contrib/ipfilter/iplang/iplang_y.y 369245 2021-02-09 13:47:46Z git2svn $
11 */
12
13#include <stdio.h>
14#include <string.h>
15#include <fcntl.h>
16#if !defined(__SVR4) && !defined(__svr4__)
17# include <strings.h>
18#else
19# include <sys/byteorder.h>
20#endif
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/param.h>
24#include <sys/time.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <stddef.h>
28#include <sys/socket.h>
29#include <net/if.h>
30#include <netinet/in.h>
31#include <netinet/in_systm.h>
32#include <netinet/ip.h>
33# include <netinet/ip_var.h>
34# include <net/route.h>
35# include <netinet/if_ether.h>
36#include <netdb.h>
37#include <arpa/nameser.h>
38#include <arpa/inet.h>
39#include <resolv.h>
40#include <ctype.h>
41#include "ipsend.h"
42#include "ip_compat.h"
43#include "ipf.h"
44#include "iplang.h"
45
46extern	int	opts;
47extern	struct ipopt_names ionames[];
48extern	int	state, state, lineNum, token;
49extern	int	yylineno;
50extern	char	yytext[];
51extern	FILE	*yyin;
52int	yylex	__P((void));
53#define	YYDEBUG 1
54int	yydebug = 1;
55
56iface_t *iflist = NULL, **iftail = &iflist;
57iface_t *cifp = NULL;
58arp_t *arplist = NULL, **arptail = &arplist, *carp = NULL;
59struct in_addr defrouter;
60send_t	sending;
61char	*sclass = NULL;
62u_short	c_chksum(u_short *, u_int, u_long);
63u_long	p_chksum(u_short *, u_int);
64
65u_long	ipbuffer[67584/sizeof(u_long)];		/* 66K */
66aniphdr_t	*aniphead = NULL, *canip = NULL, **aniptail = &aniphead;
67ip_t		*ip = NULL;
68udphdr_t	*udp = NULL;
69tcphdr_t	*tcp = NULL;
70icmphdr_t	*icmp = NULL;
71
72struct statetoopt {
73	int	sto_st;
74	int	sto_op;
75};
76
77struct	in_addr getipv4addr(char *arg);
78u_short	getportnum(char *, char *);
79struct	ether_addr *geteaddr(char *, struct ether_addr *);
80void	*new_header(int);
81void	free_aniplist(void);
82void	inc_anipheaders(int);
83void	new_data(void);
84void	set_datalen(char **);
85void	set_datafile(char **);
86void	set_data(char **);
87void	new_packet(void);
88void	set_ipv4proto(char **);
89void	set_ipv4src(char **);
90void	set_ipv4dst(char **);
91void	set_ipv4off(char **);
92void	set_ipv4v(char **);
93void	set_ipv4hl(char **);
94void	set_ipv4ttl(char **);
95void	set_ipv4tos(char **);
96void	set_ipv4id(char **);
97void	set_ipv4sum(char **);
98void	set_ipv4len(char **);
99void	new_tcpheader(void);
100void	set_tcpsport(char **);
101void	set_tcpdport(char **);
102void	set_tcpseq(char **);
103void	set_tcpack(char **);
104void	set_tcpoff(char **);
105void	set_tcpurp(char **);
106void	set_tcpwin(char **);
107void	set_tcpsum(char **);
108void	set_tcpflags(char **);
109void	set_tcpopt(int, char **);
110void	end_tcpopt(void);
111void	new_udpheader(void);
112void	set_udplen(char **);
113void	set_udpsum(char **);
114void	prep_packet(void);
115void	packet_done(void);
116void	new_interface(void);
117void	check_interface(void);
118void	set_ifname(char **);
119void	set_ifmtu(int);
120void	set_ifv4addr(char **);
121void	set_ifeaddr(char **);
122void	new_arp(void);
123void	set_arpeaddr(char **);
124void	set_arpv4addr(char **);
125void	reset_send(void);
126void	set_sendif(char **);
127void	set_sendvia(char **);
128void	set_defaultrouter(char **);
129void	new_icmpheader(void);
130void	set_icmpcode(int);
131void	set_icmptype(int);
132void	set_icmpcodetok(char **);
133void	set_icmptypetok(char **);
134void	set_icmpid(int);
135void	set_icmpseq(int);
136void	set_icmpotime(int);
137void	set_icmprtime(int);
138void	set_icmpttime(int);
139void	set_icmpmtu(int);
140void	set_redir(int, char **);
141void	new_ipv4opt(void);
142void	set_icmppprob(int);
143void	add_ipopt(int, void *);
144void	end_ipopt(void);
145void	set_secclass(char **);
146void	free_anipheader(void);
147void	end_ipv4(void);
148void	end_icmp(void);
149void	end_udp(void);
150void	end_tcp(void);
151void	end_data(void);
152void	yyerror(char *);
153void	iplang(FILE *);
154int	arp_getipv4(char *, char *);
155int	yyparse(void);
156%}
157%union {
158	char	*str;
159	int	num;
160}
161%token	<num> IL_NUMBER
162%type	<num> number digits optnumber
163%token	<str> IL_TOKEN
164%type	<str> token optoken
165%token	IL_HEXDIGIT IL_COLON IL_DOT IL_EOF IL_COMMENT
166%token	IL_INTERFACE IL_IFNAME IL_MTU IL_EADDR
167%token	IL_IPV4 IL_V4PROTO IL_V4SRC IL_V4DST IL_V4OFF IL_V4V IL_V4HL IL_V4TTL
168%token	IL_V4TOS IL_V4SUM IL_V4LEN IL_V4OPT IL_V4ID
169%token	IL_TCP IL_SPORT IL_DPORT IL_TCPFL IL_TCPSEQ IL_TCPACK IL_TCPOFF
170%token	IL_TCPWIN IL_TCPSUM IL_TCPURP IL_TCPOPT IL_TCPO_NOP IL_TCPO_EOL
171%token	IL_TCPO_MSS IL_TCPO_WSCALE IL_TCPO_TS
172%token	IL_UDP IL_UDPLEN IL_UDPSUM
173%token	IL_ICMP IL_ICMPTYPE IL_ICMPCODE
174%token	IL_SEND IL_VIA
175%token	IL_ARP
176%token	IL_DEFROUTER
177%token	IL_SUM IL_OFF IL_LEN IL_V4ADDR IL_OPT
178%token	IL_DATA IL_DLEN IL_DVALUE IL_DFILE
179%token	IL_IPO_NOP IL_IPO_RR IL_IPO_ZSU IL_IPO_MTUP IL_IPO_MTUR IL_IPO_EOL
180%token	IL_IPO_TS IL_IPO_TR IL_IPO_SEC IL_IPO_LSRR IL_IPO_ESEC
181%token	IL_IPO_SATID IL_IPO_SSRR IL_IPO_ADDEXT IL_IPO_VISA IL_IPO_IMITD
182%token	IL_IPO_EIP IL_IPO_FINN IL_IPO_SECCLASS IL_IPO_CIPSO IL_IPO_ENCODE
183%token	<str> IL_IPS_RESERV4 IL_IPS_TOPSECRET IL_IPS_SECRET IL_IPS_RESERV3
184%token	<str> IL_IPS_CONFID IL_IPS_UNCLASS IL_IPS_RESERV2 IL_IPS_RESERV1
185%token	IL_ICMP_ECHOREPLY IL_ICMP_UNREACH IL_ICMP_UNREACH_NET
186%token	IL_ICMP_UNREACH_HOST IL_ICMP_UNREACH_PROTOCOL IL_ICMP_UNREACH_PORT
187%token	IL_ICMP_UNREACH_NEEDFRAG IL_ICMP_UNREACH_SRCFAIL
188%token	IL_ICMP_UNREACH_NET_UNKNOWN IL_ICMP_UNREACH_HOST_UNKNOWN
189%token	IL_ICMP_UNREACH_ISOLATED IL_ICMP_UNREACH_NET_PROHIB
190%token	IL_ICMP_UNREACH_HOST_PROHIB IL_ICMP_UNREACH_TOSNET
191%token	IL_ICMP_UNREACH_TOSHOST IL_ICMP_UNREACH_FILTER_PROHIB
192%token	IL_ICMP_UNREACH_HOST_PRECEDENCE IL_ICMP_UNREACH_PRECEDENCE_CUTOFF
193%token	IL_ICMP_SOURCEQUENCH IL_ICMP_REDIRECT IL_ICMP_REDIRECT_NET
194%token	IL_ICMP_REDIRECT_HOST IL_ICMP_REDIRECT_TOSNET
195%token	IL_ICMP_REDIRECT_TOSHOST IL_ICMP_ECHO IL_ICMP_ROUTERADVERT
196%token	IL_ICMP_ROUTERSOLICIT IL_ICMP_TIMXCEED IL_ICMP_TIMXCEED_INTRANS
197%token	IL_ICMP_TIMXCEED_REASS IL_ICMP_PARAMPROB IL_ICMP_PARAMPROB_OPTABSENT
198%token	IL_ICMP_TSTAMP IL_ICMP_TSTAMPREPLY IL_ICMP_IREQ IL_ICMP_IREQREPLY
199%token	IL_ICMP_MASKREQ IL_ICMP_MASKREPLY IL_ICMP_SEQ IL_ICMP_ID
200%token	IL_ICMP_OTIME IL_ICMP_RTIME IL_ICMP_TTIME
201
202%%
203file:	line
204	| line file
205	| IL_COMMENT
206	| IL_COMMENT file
207	;
208
209line:	iface
210	| arp
211	| send
212	| defrouter
213	| ipline
214	;
215
216iface:  ifhdr '{' ifaceopts '}' ';'	{ check_interface(); }
217	;
218
219ifhdr:	IL_INTERFACE			{ new_interface(); }
220	;
221
222ifaceopts:
223	ifaceopt
224	| ifaceopt ifaceopts
225	;
226
227ifaceopt:
228	IL_IFNAME token			{ set_ifname(&$2); }
229	| IL_MTU number			{ set_ifmtu($2); }
230	| IL_V4ADDR token		{ set_ifv4addr(&$2); }
231	| IL_EADDR token		{ set_ifeaddr(&$2); }
232	;
233
234send:   sendhdr '{' sendbody '}' ';'	{ packet_done(); }
235	| sendhdr ';'			{ packet_done(); }
236	;
237
238sendhdr:
239	IL_SEND				{ reset_send(); }
240	;
241
242sendbody:
243	sendopt
244	| sendbody sendopt
245	;
246
247sendopt:
248	IL_IFNAME token			{ set_sendif(&$2); }
249	| IL_VIA token			{ set_sendvia(&$2); }
250	;
251
252arp:    arphdr '{' arpbody '}' ';'
253	;
254
255arphdr:	IL_ARP				{ new_arp(); }
256	;
257
258arpbody:
259	arpopt
260	| arpbody arpopt
261	;
262
263arpopt: IL_V4ADDR token			{ set_arpv4addr(&$2); }
264	| IL_EADDR token		{ set_arpeaddr(&$2); }
265	;
266
267defrouter:
268	IL_DEFROUTER token		{ set_defaultrouter(&$2); }
269	;
270
271bodyline:
272	ipline
273	| tcp tcpline
274	| udp udpline
275	| icmp icmpline
276	| data dataline
277	;
278
279ipline:	ipv4 '{' ipv4body '}' ';'	{ end_ipv4(); }
280	;
281
282ipv4:	IL_IPV4				{ new_packet(); }
283
284ipv4body:
285	ipv4type
286	| ipv4type ipv4body
287	| bodyline
288	;
289
290ipv4type:
291	IL_V4PROTO token		{ set_ipv4proto(&$2); }
292	| IL_V4SRC token		{ set_ipv4src(&$2); }
293	| IL_V4DST token		{ set_ipv4dst(&$2); }
294	| IL_V4OFF token		{ set_ipv4off(&$2); }
295	| IL_V4V token			{ set_ipv4v(&$2); }
296	| IL_V4HL token			{ set_ipv4hl(&$2); }
297	| IL_V4ID token			{ set_ipv4id(&$2); }
298	| IL_V4TTL token		{ set_ipv4ttl(&$2); }
299	| IL_V4TOS token		{ set_ipv4tos(&$2); }
300	| IL_V4SUM token		{ set_ipv4sum(&$2); }
301	| IL_V4LEN token		{ set_ipv4len(&$2); }
302	| ipv4opt '{' ipv4optlist '}' ';'	{ end_ipopt(); }
303	;
304
305tcp:	IL_TCP				{ new_tcpheader(); }
306	;
307
308tcpline:
309	'{' tcpheader '}' ';'		{ end_tcp(); }
310	;
311
312tcpheader:
313	tcpbody
314	| tcpbody tcpheader
315	| bodyline
316	;
317
318tcpbody:
319	IL_SPORT token			{ set_tcpsport(&$2); }
320	| IL_DPORT token		{ set_tcpdport(&$2); }
321	| IL_TCPSEQ token		{ set_tcpseq(&$2); }
322	| IL_TCPACK token		{ set_tcpack(&$2); }
323	| IL_TCPOFF token		{ set_tcpoff(&$2); }
324	| IL_TCPURP token		{ set_tcpurp(&$2); }
325	| IL_TCPWIN token		{ set_tcpwin(&$2); }
326	| IL_TCPSUM token		{ set_tcpsum(&$2); }
327	| IL_TCPFL token		{ set_tcpflags(&$2); }
328	| IL_TCPOPT '{' tcpopts '}' ';'	{ end_tcpopt(); }
329	;
330
331tcpopts:
332	| tcpopt tcpopts
333	;
334
335tcpopt:	IL_TCPO_NOP ';'			{ set_tcpopt(IL_TCPO_NOP, NULL); }
336	| IL_TCPO_EOL ';'		{ set_tcpopt(IL_TCPO_EOL, NULL); }
337	| IL_TCPO_MSS optoken		{ set_tcpopt(IL_TCPO_MSS,&$2);}
338	| IL_TCPO_WSCALE optoken	{ set_tcpopt(IL_TCPO_WSCALE,&$2);}
339	| IL_TCPO_TS optoken		{ set_tcpopt(IL_TCPO_TS, &$2);}
340	;
341
342udp:	IL_UDP				{ new_udpheader(); }
343	;
344
345udpline:
346	'{' udpheader '}' ';'		{ end_udp(); }
347	;
348
349
350udpheader:
351	udpbody
352	| udpbody udpheader
353	| bodyline
354	;
355
356udpbody:
357	IL_SPORT token			{ set_tcpsport(&$2); }
358	| IL_DPORT token		{ set_tcpdport(&$2); }
359	| IL_UDPLEN token		{ set_udplen(&$2); }
360	| IL_UDPSUM token		{ set_udpsum(&$2); }
361	;
362
363icmp:	IL_ICMP				{ new_icmpheader(); }
364	;
365
366icmpline:
367	'{' icmpbody '}' ';'		{ end_icmp(); }
368	;
369
370icmpbody:
371	icmpheader
372	| icmpheader bodyline
373	;
374
375icmpheader:
376	IL_ICMPTYPE icmptype
377	| IL_ICMPTYPE icmptype icmpcode
378	;
379
380icmpcode:
381	IL_ICMPCODE token		{ set_icmpcodetok(&$2); }
382	;
383
384icmptype:
385	IL_ICMP_ECHOREPLY ';'		{ set_icmptype(ICMP_ECHOREPLY); }
386	| IL_ICMP_ECHOREPLY '{' icmpechoopts '}' ';'
387	| unreach
388	| IL_ICMP_SOURCEQUENCH ';'	{ set_icmptype(ICMP_SOURCEQUENCH); }
389	| redirect
390	| IL_ICMP_ROUTERADVERT ';'	{ set_icmptype(ICMP_ROUTERADVERT); }
391	| IL_ICMP_ROUTERSOLICIT ';'	{ set_icmptype(ICMP_ROUTERSOLICIT); }
392	| IL_ICMP_ECHO ';'		{ set_icmptype(ICMP_ECHO); }
393	| IL_ICMP_ECHO '{' icmpechoopts '}' ';'
394	| IL_ICMP_TIMXCEED ';'		{ set_icmptype(ICMP_TIMXCEED); }
395	| IL_ICMP_TIMXCEED '{' exceed '}' ';'
396	| IL_ICMP_TSTAMP ';'		{ set_icmptype(ICMP_TSTAMP); }
397	| IL_ICMP_TSTAMPREPLY ';'	{ set_icmptype(ICMP_TSTAMPREPLY); }
398	| IL_ICMP_TSTAMPREPLY '{' icmptsopts '}' ';'
399	| IL_ICMP_IREQ ';'		{ set_icmptype(ICMP_IREQ); }
400	| IL_ICMP_IREQREPLY ';'		{ set_icmptype(ICMP_IREQREPLY); }
401	| IL_ICMP_IREQREPLY '{' data dataline '}' ';'
402	| IL_ICMP_MASKREQ ';'		{ set_icmptype(ICMP_MASKREQ); }
403	| IL_ICMP_MASKREPLY ';'		{ set_icmptype(ICMP_MASKREPLY); }
404	| IL_ICMP_MASKREPLY '{' token '}' ';'
405	| IL_ICMP_PARAMPROB ';'		{ set_icmptype(ICMP_PARAMPROB); }
406	| IL_ICMP_PARAMPROB '{' paramprob '}' ';'
407	| IL_TOKEN ';'			{ set_icmptypetok(&$1); }
408	;
409
410icmpechoopts:
411	| icmpechoopts icmpecho
412	;
413
414icmpecho:
415	IL_ICMP_SEQ number 		{ set_icmpseq($2); }
416	| IL_ICMP_ID number		{ set_icmpid($2); }
417	;
418
419icmptsopts:
420	| icmptsopts icmpts ';'
421	;
422
423icmpts: IL_ICMP_OTIME number 		{ set_icmpotime($2); }
424	| IL_ICMP_RTIME number 		{ set_icmprtime($2); }
425	| IL_ICMP_TTIME number 		{ set_icmpttime($2); }
426	;
427
428unreach:
429	IL_ICMP_UNREACH
430	| IL_ICMP_UNREACH '{' unreachopts '}' ';'
431	;
432
433unreachopts:
434	IL_ICMP_UNREACH_NET line
435	| IL_ICMP_UNREACH_HOST line
436	| IL_ICMP_UNREACH_PROTOCOL line
437	| IL_ICMP_UNREACH_PORT line
438	| IL_ICMP_UNREACH_NEEDFRAG number ';'	{ set_icmpmtu($2); }
439	| IL_ICMP_UNREACH_SRCFAIL line
440	| IL_ICMP_UNREACH_NET_UNKNOWN line
441	| IL_ICMP_UNREACH_HOST_UNKNOWN line
442	| IL_ICMP_UNREACH_ISOLATED line
443	| IL_ICMP_UNREACH_NET_PROHIB line
444	| IL_ICMP_UNREACH_HOST_PROHIB line
445	| IL_ICMP_UNREACH_TOSNET line
446	| IL_ICMP_UNREACH_TOSHOST line
447	| IL_ICMP_UNREACH_FILTER_PROHIB line
448	| IL_ICMP_UNREACH_HOST_PRECEDENCE line
449	| IL_ICMP_UNREACH_PRECEDENCE_CUTOFF line
450	;
451
452redirect:
453	IL_ICMP_REDIRECT
454	| IL_ICMP_REDIRECT '{' redirectopts '}' ';'
455	;
456
457redirectopts:
458	| IL_ICMP_REDIRECT_NET token		{ set_redir(0, &$2); }
459	| IL_ICMP_REDIRECT_HOST token		{ set_redir(1, &$2); }
460	| IL_ICMP_REDIRECT_TOSNET token		{ set_redir(2, &$2); }
461	| IL_ICMP_REDIRECT_TOSHOST token	{ set_redir(3, &$2); }
462	;
463
464exceed:
465	IL_ICMP_TIMXCEED_INTRANS line
466	| IL_ICMP_TIMXCEED_REASS line
467	;
468
469paramprob:
470	IL_ICMP_PARAMPROB_OPTABSENT
471	| IL_ICMP_PARAMPROB_OPTABSENT paraprobarg
472
473paraprobarg:
474	'{' number '}' ';'		{ set_icmppprob($2); }
475	;
476
477ipv4opt:	IL_V4OPT		{ new_ipv4opt(); }
478	;
479
480ipv4optlist:
481	| ipv4opts ipv4optlist
482	;
483
484ipv4opts:
485	IL_IPO_NOP ';'			{ add_ipopt(IL_IPO_NOP, NULL); }
486	| IL_IPO_RR optnumber		{ add_ipopt(IL_IPO_RR, &$2); }
487	| IL_IPO_ZSU ';'		{ add_ipopt(IL_IPO_ZSU, NULL); }
488	| IL_IPO_MTUP ';'		{ add_ipopt(IL_IPO_MTUP, NULL); }
489	| IL_IPO_MTUR ';'		{ add_ipopt(IL_IPO_MTUR, NULL); }
490	| IL_IPO_ENCODE ';'		{ add_ipopt(IL_IPO_ENCODE, NULL); }
491	| IL_IPO_TS ';'			{ add_ipopt(IL_IPO_TS, NULL); }
492	| IL_IPO_TR ';'			{ add_ipopt(IL_IPO_TR, NULL); }
493	| IL_IPO_SEC ';'		{ add_ipopt(IL_IPO_SEC, NULL); }
494	| IL_IPO_SECCLASS secclass	{ add_ipopt(IL_IPO_SECCLASS, sclass); }
495	| IL_IPO_LSRR token		{ add_ipopt(IL_IPO_LSRR,&$2); }
496	| IL_IPO_ESEC ';'		{ add_ipopt(IL_IPO_ESEC, NULL); }
497	| IL_IPO_CIPSO ';'		{ add_ipopt(IL_IPO_CIPSO, NULL); }
498	| IL_IPO_SATID optnumber	{ add_ipopt(IL_IPO_SATID,&$2);}
499	| IL_IPO_SSRR token		{ add_ipopt(IL_IPO_SSRR,&$2); }
500	| IL_IPO_ADDEXT ';'		{ add_ipopt(IL_IPO_ADDEXT, NULL); }
501	| IL_IPO_VISA ';'		{ add_ipopt(IL_IPO_VISA, NULL); }
502	| IL_IPO_IMITD ';'		{ add_ipopt(IL_IPO_IMITD, NULL); }
503	| IL_IPO_EIP ';'		{ add_ipopt(IL_IPO_EIP, NULL); }
504	| IL_IPO_FINN ';'		{ add_ipopt(IL_IPO_FINN, NULL); }
505	;
506
507secclass:
508	IL_IPS_RESERV4 ';'		{ set_secclass(&$1); }
509	| IL_IPS_TOPSECRET ';'		{ set_secclass(&$1); }
510	| IL_IPS_SECRET ';'		{ set_secclass(&$1); }
511	| IL_IPS_RESERV3 ';'		{ set_secclass(&$1); }
512	| IL_IPS_CONFID ';'		{ set_secclass(&$1); }
513	| IL_IPS_UNCLASS ';'		{ set_secclass(&$1); }
514	| IL_IPS_RESERV2 ';'		{ set_secclass(&$1); }
515	| IL_IPS_RESERV1 ';'		{ set_secclass(&$1); }
516	;
517
518data:	IL_DATA				{ new_data(); }
519	;
520
521dataline:
522	'{' databody '}' ';'		{ end_data(); }
523	;
524
525databody: dataopts
526	| dataopts databody
527	;
528
529dataopts:
530	IL_DLEN token			{ set_datalen(&$2); }
531	| IL_DVALUE token 		{ set_data(&$2); }
532	| IL_DFILE token 		{ set_datafile(&$2); }
533	;
534
535token: IL_TOKEN ';'
536	;
537
538optoken: ';'				{ $$ = ""; }
539	| token
540	;
541
542number: digits ';'
543	;
544
545optnumber: ';'				{ $$ = 0; }
546	| number
547	;
548
549digits:	IL_NUMBER
550	| digits IL_NUMBER
551	;
552%%
553
554struct	statetoopt	toipopts[] = {
555	{ IL_IPO_NOP,		IPOPT_NOP },
556	{ IL_IPO_RR,		IPOPT_RR },
557	{ IL_IPO_ZSU,		IPOPT_ZSU },
558	{ IL_IPO_MTUP,		IPOPT_MTUP },
559	{ IL_IPO_MTUR,		IPOPT_MTUR },
560	{ IL_IPO_ENCODE,	IPOPT_ENCODE },
561	{ IL_IPO_TS,		IPOPT_TS },
562	{ IL_IPO_TR,		IPOPT_TR },
563	{ IL_IPO_SEC,		IPOPT_SECURITY },
564	{ IL_IPO_SECCLASS,	IPOPT_SECURITY },
565	{ IL_IPO_LSRR,		IPOPT_LSRR },
566	{ IL_IPO_ESEC,		IPOPT_E_SEC },
567	{ IL_IPO_CIPSO,		IPOPT_CIPSO },
568	{ IL_IPO_SATID,		IPOPT_SATID },
569	{ IL_IPO_SSRR,		IPOPT_SSRR },
570	{ IL_IPO_ADDEXT,	IPOPT_ADDEXT },
571	{ IL_IPO_VISA,		IPOPT_VISA },
572	{ IL_IPO_IMITD,		IPOPT_IMITD },
573	{ IL_IPO_EIP,		IPOPT_EIP },
574	{ IL_IPO_FINN,		IPOPT_FINN },
575	{ 0, 0 }
576};
577
578struct	statetoopt	tosecopts[] = {
579	{ IL_IPS_RESERV4,	IPSO_CLASS_RES4 },
580	{ IL_IPS_TOPSECRET,	IPSO_CLASS_TOPS },
581	{ IL_IPS_SECRET,	IPSO_CLASS_SECR },
582	{ IL_IPS_RESERV3,	IPSO_CLASS_RES3 },
583	{ IL_IPS_CONFID,	IPSO_CLASS_CONF },
584	{ IL_IPS_UNCLASS,	IPSO_CLASS_UNCL },
585	{ IL_IPS_RESERV2,	IPSO_CLASS_RES2 },
586	{ IL_IPS_RESERV1,	IPSO_CLASS_RES1 },
587	{ 0, 0 }
588};
589
590
591struct in_addr getipv4addr(arg)
592char *arg;
593{
594	struct hostent *hp;
595	struct in_addr in;
596
597	in.s_addr = 0xffffffff;
598
599	if ((hp = gethostbyname(arg)))
600		bcopy(hp->h_addr, &in.s_addr, sizeof(struct in_addr));
601	else
602		in.s_addr = inet_addr(arg);
603	return in;
604}
605
606
607u_short getportnum(pr, name)
608char *pr, *name;
609{
610	struct servent *sp;
611
612	if (!(sp = getservbyname(name, pr)))
613		return htons(atoi(name));
614	return sp->s_port;
615}
616
617
618struct ether_addr *geteaddr(arg, buf)
619char *arg;
620struct ether_addr *buf;
621{
622	struct ether_addr *e;
623
624	e = ether_aton(arg);
625	if (!e)
626		fprintf(stderr, "Invalid ethernet address: %s\n", arg);
627	else
628# ifdef	__FreeBSD__
629		bcopy(e->octet, buf->octet, sizeof(e->octet));
630# else
631		bcopy(e->ether_addr_octet, buf->ether_addr_octet,
632		      sizeof(e->ether_addr_octet));
633# endif
634	return e;
635}
636
637
638void *new_header(type)
639int type;
640{
641	aniphdr_t *aip, *oip = canip;
642	int	sz = 0;
643
644	aip = (aniphdr_t *)calloc(1, sizeof(*aip));
645	*aniptail = aip;
646	aniptail = &aip->ah_next;
647	aip->ah_p = type;
648	aip->ah_prev = oip;
649	canip = aip;
650
651	if (type == IPPROTO_UDP)
652		sz = sizeof(udphdr_t);
653	else if (type == IPPROTO_TCP)
654		sz = sizeof(tcphdr_t);
655	else if (type == IPPROTO_ICMP)
656		sz = sizeof(icmphdr_t);
657	else if (type == IPPROTO_IP)
658		sz = sizeof(ip_t);
659
660	if (oip)
661		canip->ah_data = oip->ah_data + oip->ah_len;
662	else
663		canip->ah_data = (char *)ipbuffer;
664
665	/*
666	 * Increase the size fields in all wrapping headers.
667	 */
668	for (aip = aniphead; aip; aip = aip->ah_next) {
669		aip->ah_len += sz;
670		if (aip->ah_p == IPPROTO_IP)
671			aip->ah_ip->ip_len += sz;
672		else if (aip->ah_p == IPPROTO_UDP)
673			aip->ah_udp->uh_ulen += sz;
674	}
675	return (void *)canip->ah_data;
676}
677
678
679void free_aniplist()
680{
681	aniphdr_t *aip, **aipp = &aniphead;
682
683	while ((aip = *aipp)) {
684		*aipp = aip->ah_next;
685		free(aip);
686	}
687	aniptail = &aniphead;
688}
689
690
691void inc_anipheaders(inc)
692int inc;
693{
694	aniphdr_t *aip;
695
696	for (aip = aniphead; aip; aip = aip->ah_next) {
697		aip->ah_len += inc;
698		if (aip->ah_p == IPPROTO_IP)
699			aip->ah_ip->ip_len += inc;
700		else if (aip->ah_p == IPPROTO_UDP)
701			aip->ah_udp->uh_ulen += inc;
702	}
703}
704
705
706void new_data()
707{
708	(void) new_header(-1);
709	canip->ah_len = 0;
710}
711
712
713void set_datalen(arg)
714char **arg;
715{
716	int	len;
717
718	len = strtol(*arg, NULL, 0);
719	inc_anipheaders(len);
720	free(*arg);
721	*arg = NULL;
722}
723
724
725void set_data(arg)
726char **arg;
727{
728	u_char *s = (u_char *)*arg, *t = (u_char *)canip->ah_data, c;
729	int len = 0, todo = 0, quote = 0, val = 0;
730
731	while ((c = *s++)) {
732		if (todo) {
733			if (ISDIGIT(c)) {
734				todo--;
735				if (c > '7') {
736					fprintf(stderr, "octal with %c!\n", c);
737					break;
738				}
739				val <<= 3;
740				val |= (c - '0');
741			}
742			if (!ISDIGIT(c) || !todo) {
743				*t++ = (u_char)(val & 0xff);
744				todo = 0;
745			}
746			if (todo)
747				continue;
748		}
749		if (quote) {
750			if (ISDIGIT(c)) {
751				todo = 2;
752				if (c > '7') {
753					fprintf(stderr, "octal with %c!\n", c);
754					break;
755				}
756				val = (c - '0');
757			} else {
758				switch (c)
759				{
760				case '\"' :
761					*t++ = '\"';
762					break;
763				case '\\' :
764					*t++ = '\\';
765					break;
766				case 'n' :
767					*t++ = '\n';
768					break;
769				case 'r' :
770					*t++ = '\r';
771					break;
772				case 't' :
773					*t++ = '\t';
774					break;
775				}
776			}
777			quote = 0;
778			continue;
779		}
780
781		if (c == '\\')
782			quote = 1;
783		else
784			*t++ = c;
785	}
786	if (todo)
787		*t++ = (u_char)(val & 0xff);
788	if (quote)
789		*t++ = '\\';
790	len = t - (u_char *)canip->ah_data;
791	inc_anipheaders(len - canip->ah_len);
792	canip->ah_len = len;
793}
794
795
796void set_datafile(arg)
797char **arg;
798{
799	struct stat sb;
800	char *file = *arg;
801	int fd, len;
802
803	if ((fd = open(file, O_RDONLY)) == -1) {
804		perror("open");
805		exit(-1);
806	}
807
808	if (fstat(fd, &sb) == -1) {
809		perror("fstat");
810		exit(-1);
811	}
812
813	if ((sb.st_size + aniphead->ah_len ) > 65535) {
814		fprintf(stderr, "data file %s too big to include.\n", file);
815		close(fd);
816		return;
817	}
818	if ((len = read(fd, canip->ah_data, sb.st_size)) == -1) {
819		perror("read");
820		close(fd);
821		return;
822	}
823	inc_anipheaders(len);
824	canip->ah_len += len;
825	close(fd);
826}
827
828
829void new_packet()
830{
831	static	u_short	id = 0;
832
833	if (!aniphead)
834		bzero((char *)ipbuffer, sizeof(ipbuffer));
835
836	ip = (ip_t *)new_header(IPPROTO_IP);
837	ip->ip_v = IPVERSION;
838	ip->ip_hl = sizeof(ip_t) >> 2;
839	ip->ip_len = sizeof(ip_t);
840	ip->ip_ttl = 63;
841	ip->ip_id = htons(id++);
842}
843
844
845void set_ipv4proto(arg)
846char **arg;
847{
848	struct protoent *pr;
849
850	if ((pr = getprotobyname(*arg)))
851		ip->ip_p = pr->p_proto;
852	else
853		if (!(ip->ip_p = atoi(*arg)))
854			fprintf(stderr, "unknown protocol %s\n", *arg);
855	free(*arg);
856	*arg = NULL;
857}
858
859
860void set_ipv4src(arg)
861char **arg;
862{
863	ip->ip_src = getipv4addr(*arg);
864	free(*arg);
865	*arg = NULL;
866}
867
868
869void set_ipv4dst(arg)
870char **arg;
871{
872	ip->ip_dst = getipv4addr(*arg);
873	free(*arg);
874	*arg = NULL;
875}
876
877
878void set_ipv4off(arg)
879char **arg;
880{
881	ip->ip_off = htons(strtol(*arg, NULL, 0));
882	free(*arg);
883	*arg = NULL;
884}
885
886
887void set_ipv4v(arg)
888char **arg;
889{
890	ip->ip_v = strtol(*arg, NULL, 0);
891	free(*arg);
892	*arg = NULL;
893}
894
895
896void set_ipv4hl(arg)
897char **arg;
898{
899	int newhl, inc;
900
901	newhl = strtol(*arg, NULL, 0);
902	inc = (newhl - ip->ip_hl) << 2;
903	ip->ip_len += inc;
904	ip->ip_hl = newhl;
905	canip->ah_len += inc;
906	free(*arg);
907	*arg = NULL;
908}
909
910
911void set_ipv4ttl(arg)
912char **arg;
913{
914	ip->ip_ttl = strtol(*arg, NULL, 0);
915	free(*arg);
916	*arg = NULL;
917}
918
919
920void set_ipv4tos(arg)
921char **arg;
922{
923	ip->ip_tos = strtol(*arg, NULL, 0);
924	free(*arg);
925	*arg = NULL;
926}
927
928
929void set_ipv4id(arg)
930char **arg;
931{
932	ip->ip_id = htons(strtol(*arg, NULL, 0));
933	free(*arg);
934	*arg = NULL;
935}
936
937
938void set_ipv4sum(arg)
939char **arg;
940{
941	ip->ip_sum = strtol(*arg, NULL, 0);
942	free(*arg);
943	*arg = NULL;
944}
945
946
947void set_ipv4len(arg)
948char **arg;
949{
950	int len;
951
952	len = strtol(*arg, NULL, 0);
953	inc_anipheaders(len - ip->ip_len);
954	ip->ip_len = len;
955	free(*arg);
956	*arg = NULL;
957}
958
959
960void new_tcpheader()
961{
962
963	if ((ip->ip_p) && (ip->ip_p != IPPROTO_TCP)) {
964		fprintf(stderr, "protocol %d specified with TCP!\n", ip->ip_p);
965		return;
966	}
967	ip->ip_p = IPPROTO_TCP;
968
969	tcp = (tcphdr_t *)new_header(IPPROTO_TCP);
970	tcp->th_win = htons(4096);
971	tcp->th_off = sizeof(*tcp) >> 2;
972}
973
974
975void set_tcpsport(arg)
976char **arg;
977{
978	u_short *port;
979	char *pr;
980
981	if (ip->ip_p == IPPROTO_UDP) {
982		port = &udp->uh_sport;
983		pr = "udp";
984	} else {
985		port = &tcp->th_sport;
986		pr = "udp";
987	}
988
989	*port = getportnum(pr, *arg);
990	free(*arg);
991	*arg = NULL;
992}
993
994
995void set_tcpdport(arg)
996char **arg;
997{
998	u_short *port;
999	char *pr;
1000
1001	if (ip->ip_p == IPPROTO_UDP) {
1002		port = &udp->uh_dport;
1003		pr = "udp";
1004	} else {
1005		port = &tcp->th_dport;
1006		pr = "udp";
1007	}
1008
1009	*port = getportnum(pr, *arg);
1010	free(*arg);
1011	*arg = NULL;
1012}
1013
1014
1015void set_tcpseq(arg)
1016char **arg;
1017{
1018	tcp->th_seq = htonl(strtol(*arg, NULL, 0));
1019	free(*arg);
1020	*arg = NULL;
1021}
1022
1023
1024void set_tcpack(arg)
1025char **arg;
1026{
1027	tcp->th_ack = htonl(strtol(*arg, NULL, 0));
1028	free(*arg);
1029	*arg = NULL;
1030}
1031
1032
1033void set_tcpoff(arg)
1034char **arg;
1035{
1036	int	off;
1037
1038	off = strtol(*arg, NULL, 0);
1039	inc_anipheaders((off - tcp->th_off) << 2);
1040	tcp->th_off = off;
1041	free(*arg);
1042	*arg = NULL;
1043}
1044
1045
1046void set_tcpurp(arg)
1047char **arg;
1048{
1049	tcp->th_urp = htons(strtol(*arg, NULL, 0));
1050	free(*arg);
1051	*arg = NULL;
1052}
1053
1054
1055void set_tcpwin(arg)
1056char **arg;
1057{
1058	tcp->th_win = htons(strtol(*arg, NULL, 0));
1059	free(*arg);
1060	*arg = NULL;
1061}
1062
1063
1064void set_tcpsum(arg)
1065char **arg;
1066{
1067	tcp->th_sum = strtol(*arg, NULL, 0);
1068	free(*arg);
1069	*arg = NULL;
1070}
1071
1072
1073void set_tcpflags(arg)
1074char **arg;
1075{
1076	static	char	flags[] = "ASURPF";
1077	static	int	flagv[] = { TH_ACK, TH_SYN, TH_URG, TH_RST, TH_PUSH,
1078				    TH_FIN } ;
1079	char *s, *t;
1080
1081	for (s = *arg; *s; s++)
1082		if (!(t = strchr(flags, *s))) {
1083			if (s - *arg) {
1084				fprintf(stderr, "unknown TCP flag %c\n", *s);
1085				break;
1086			}
1087			tcp->th_flags = strtol(*arg, NULL, 0);
1088			break;
1089		} else
1090			tcp->th_flags |= flagv[t - flags];
1091	free(*arg);
1092	*arg = NULL;
1093}
1094
1095
1096void set_tcpopt(state, arg)
1097int state;
1098char **arg;
1099{
1100	u_char *s;
1101	int val, len, val2, pad, optval;
1102
1103	if (arg && *arg)
1104		val = atoi(*arg);
1105	else
1106		val = 0;
1107
1108	s = (u_char *)tcp + sizeof(*tcp) + canip->ah_optlen;
1109	switch (state)
1110	{
1111	case IL_TCPO_EOL :
1112		optval = 0;
1113		len = 1;
1114		break;
1115	case IL_TCPO_NOP :
1116		optval = 1;
1117		len = 1;
1118		break;
1119	case IL_TCPO_MSS :
1120		optval = 2;
1121		len = 4;
1122		break;
1123	case IL_TCPO_WSCALE :
1124		optval = 3;
1125		len = 3;
1126		break;
1127	case IL_TCPO_TS :
1128		optval = 8;
1129		len = 10;
1130		break;
1131	default :
1132		optval = 0;
1133		len = 0;
1134		break;
1135	}
1136
1137	if (len > 1) {
1138		/*
1139		 * prepend padding - if required.
1140		 */
1141		if (len & 3)
1142			for (pad = 4 - (len & 3); pad; pad--) {
1143				*s++ = 1;
1144				canip->ah_optlen++;
1145			}
1146		/*
1147		 * build tcp option
1148		 */
1149		*s++ = (u_char)optval;
1150		*s++ = (u_char)len;
1151		if (len > 2) {
1152			if (len == 3) {		/* 1 byte - char */
1153				*s++ = (u_char)val;
1154			} else if (len == 4) {	/* 2 bytes - short */
1155				*s++ = (u_char)((val >> 8) & 0xff);
1156				*s++ = (u_char)(val & 0xff);
1157			} else if (len >= 6) {	/* 4 bytes - long */
1158				val2 = htonl(val);
1159				bcopy((char *)&val2, s, 4);
1160			}
1161			s += (len - 2);
1162		}
1163	} else
1164		*s++ = (u_char)optval;
1165
1166	canip->ah_lastopt = optval;
1167	canip->ah_optlen += len;
1168
1169	if (arg && *arg) {
1170		free(*arg);
1171		*arg = NULL;
1172	}
1173}
1174
1175
1176void end_tcpopt()
1177{
1178	int pad;
1179	char *s = (char *)tcp;
1180
1181	s += sizeof(*tcp) + canip->ah_optlen;
1182	/*
1183	 * pad out so that we have a multiple of 4 bytes in size fo the
1184	 * options.  make sure last byte is EOL.
1185	 */
1186	if (canip->ah_optlen & 3) {
1187		if (canip->ah_lastopt != 1) {
1188			for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
1189				*s++ = 1;
1190				canip->ah_optlen++;
1191			}
1192			canip->ah_optlen++;
1193		} else {
1194			s -= 1;
1195
1196			for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
1197				*s++ = 1;
1198				canip->ah_optlen++;
1199			}
1200		}
1201		*s++ = 0;
1202	}
1203	tcp->th_off = (sizeof(*tcp) + canip->ah_optlen) >> 2;
1204	inc_anipheaders(canip->ah_optlen);
1205}
1206
1207
1208void new_udpheader()
1209{
1210	if ((ip->ip_p) && (ip->ip_p != IPPROTO_UDP)) {
1211		fprintf(stderr, "protocol %d specified with UDP!\n", ip->ip_p);
1212		return;
1213	}
1214	ip->ip_p = IPPROTO_UDP;
1215
1216	udp = (udphdr_t *)new_header(IPPROTO_UDP);
1217	udp->uh_ulen = sizeof(*udp);
1218}
1219
1220
1221void set_udplen(arg)
1222char **arg;
1223{
1224	int len;
1225
1226	len = strtol(*arg, NULL, 0);
1227	inc_anipheaders(len - udp->uh_ulen);
1228	udp->uh_ulen = len;
1229	free(*arg);
1230	*arg = NULL;
1231}
1232
1233
1234void set_udpsum(arg)
1235char **arg;
1236{
1237	udp->uh_sum = strtol(*arg, NULL, 0);
1238	free(*arg);
1239	*arg = NULL;
1240}
1241
1242
1243void prep_packet()
1244{
1245	iface_t *ifp;
1246	struct in_addr gwip;
1247
1248	ifp = sending.snd_if;
1249	if (!ifp) {
1250		fprintf(stderr, "no interface defined for sending!\n");
1251		return;
1252	}
1253	if (ifp->if_fd == -1)
1254		ifp->if_fd = initdevice(ifp->if_name, 5);
1255	gwip = sending.snd_gw;
1256	if (!gwip.s_addr) {
1257		if (aniphead == NULL) {
1258			fprintf(stderr,
1259				"no destination address defined for sending\n");
1260			return;
1261		}
1262		gwip = aniphead->ah_ip->ip_dst;
1263	}
1264	(void) send_ip(ifp->if_fd, ifp->if_MTU, (ip_t *)ipbuffer, gwip, 2);
1265}
1266
1267
1268void packet_done()
1269{
1270	char    outline[80];
1271	int     i, j, k;
1272	u_char  *s = (u_char *)ipbuffer, *t = (u_char *)outline;
1273
1274	if (opts & OPT_VERBOSE) {
1275		ip->ip_len = htons(ip->ip_len);
1276		for (i = ntohs(ip->ip_len), j = 0; i; i--, j++, s++) {
1277			if (j && !(j & 0xf)) {
1278				*t++ = '\n';
1279				*t = '\0';
1280				fputs(outline, stdout);
1281				fflush(stdout);
1282				t = (u_char *)outline;
1283				*t = '\0';
1284			}
1285			sprintf((char *)t, "%02x", *s & 0xff);
1286			t += 2;
1287			if (!((j + 1) & 0xf)) {
1288				s -= 15;
1289				sprintf((char *)t, "	");
1290				t += 8;
1291				for (k = 16; k; k--, s++)
1292					*t++ = (isprint(*s) ? *s : '.');
1293				s--;
1294			}
1295
1296			if ((j + 1) & 0xf)
1297				*t++ = ' ';;
1298		}
1299
1300		if (j & 0xf) {
1301			for (k = 16 - (j & 0xf); k; k--) {
1302				*t++ = ' ';
1303				*t++ = ' ';
1304				*t++ = ' ';
1305			}
1306			sprintf((char *)t, "       ");
1307			t += 7;
1308			s -= j & 0xf;
1309			for (k = j & 0xf; k; k--, s++)
1310				*t++ = (isprint(*s) ? *s : '.');
1311			*t++ = '\n';
1312			*t = '\0';
1313		}
1314		fputs(outline, stdout);
1315		fflush(stdout);
1316		ip->ip_len = ntohs(ip->ip_len);
1317	}
1318
1319	prep_packet();
1320	free_aniplist();
1321}
1322
1323
1324void new_interface()
1325{
1326	cifp = (iface_t *)calloc(1, sizeof(iface_t));
1327	*iftail = cifp;
1328	iftail = &cifp->if_next;
1329	cifp->if_fd = -1;
1330}
1331
1332
1333void check_interface()
1334{
1335	if (!cifp->if_name || !*cifp->if_name)
1336		fprintf(stderr, "No interface name given!\n");
1337	if (!cifp->if_MTU || !*cifp->if_name)
1338		fprintf(stderr, "Interface %s has an MTU of 0!\n",
1339			cifp->if_name);
1340}
1341
1342
1343void set_ifname(arg)
1344char **arg;
1345{
1346	cifp->if_name = *arg;
1347	*arg = NULL;
1348}
1349
1350
1351void set_ifmtu(arg)
1352int arg;
1353{
1354	cifp->if_MTU = arg;
1355}
1356
1357
1358void set_ifv4addr(arg)
1359char **arg;
1360{
1361	cifp->if_addr = getipv4addr(*arg);
1362	free(*arg);
1363	*arg = NULL;
1364}
1365
1366
1367void set_ifeaddr(arg)
1368char **arg;
1369{
1370	(void) geteaddr(*arg, &cifp->if_eaddr);
1371	free(*arg);
1372	*arg = NULL;
1373}
1374
1375
1376void new_arp()
1377{
1378	carp = (arp_t *)calloc(1, sizeof(arp_t));
1379	*arptail = carp;
1380	arptail = &carp->arp_next;
1381}
1382
1383
1384void set_arpeaddr(arg)
1385char **arg;
1386{
1387	(void) geteaddr(*arg, &carp->arp_eaddr);
1388	free(*arg);
1389	*arg = NULL;
1390}
1391
1392
1393void set_arpv4addr(arg)
1394char **arg;
1395{
1396	carp->arp_addr = getipv4addr(*arg);
1397	free(*arg);
1398	*arg = NULL;
1399}
1400
1401
1402int arp_getipv4(ip, addr)
1403char *ip;
1404char *addr;
1405{
1406	arp_t *a;
1407
1408	for (a = arplist; a; a = a->arp_next)
1409		if (!bcmp(ip, (char *)&a->arp_addr, 4)) {
1410			bcopy((char *)&a->arp_eaddr, addr, 6);
1411			return 0;
1412		}
1413	return -1;
1414}
1415
1416
1417void reset_send()
1418{
1419	sending.snd_if = iflist;
1420	sending.snd_gw = defrouter;
1421}
1422
1423
1424void set_sendif(arg)
1425char **arg;
1426{
1427	iface_t	*ifp;
1428
1429	for (ifp = iflist; ifp; ifp = ifp->if_next)
1430		if (ifp->if_name && !strcmp(ifp->if_name, *arg))
1431			break;
1432	sending.snd_if = ifp;
1433	if (!ifp)
1434		fprintf(stderr, "couldn't find interface %s\n", *arg);
1435	free(*arg);
1436	*arg = NULL;
1437}
1438
1439
1440void set_sendvia(arg)
1441char **arg;
1442{
1443	sending.snd_gw = getipv4addr(*arg);
1444	free(*arg);
1445	*arg = NULL;
1446}
1447
1448
1449void set_defaultrouter(arg)
1450char **arg;
1451{
1452	defrouter = getipv4addr(*arg);
1453	free(*arg);
1454	*arg = NULL;
1455}
1456
1457
1458void new_icmpheader()
1459{
1460	if ((ip->ip_p) && (ip->ip_p != IPPROTO_ICMP)) {
1461		fprintf(stderr, "protocol %d specified with ICMP!\n",
1462			ip->ip_p);
1463		return;
1464	}
1465	ip->ip_p = IPPROTO_ICMP;
1466	icmp = (icmphdr_t *)new_header(IPPROTO_ICMP);
1467}
1468
1469
1470void set_icmpcode(code)
1471int code;
1472{
1473	icmp->icmp_code = code;
1474}
1475
1476
1477void set_icmptype(type)
1478int type;
1479{
1480	icmp->icmp_type = type;
1481}
1482
1483
1484void set_icmpcodetok(code)
1485char **code;
1486{
1487	char	*s;
1488	int	i;
1489
1490	for (i = 0; (s = icmpcodes[i]); i++)
1491		if (!strcmp(s, *code)) {
1492			icmp->icmp_code = i;
1493			break;
1494		}
1495	if (!s)
1496		fprintf(stderr, "unknown ICMP code %s\n", *code);
1497	free(*code);
1498	*code = NULL;
1499}
1500
1501
1502void set_icmptypetok(type)
1503char **type;
1504{
1505	char	*s;
1506	int	i, done = 0;
1507
1508	for (i = 0; !(s = icmptypes[i]) || strcmp(s, "END"); i++)
1509		if (s && !strcmp(s, *type)) {
1510			icmp->icmp_type = i;
1511			done = 1;
1512			break;
1513		}
1514	if (!done)
1515		fprintf(stderr, "unknown ICMP type %s\n", *type);
1516	free(*type);
1517	*type = NULL;
1518}
1519
1520
1521void set_icmpid(arg)
1522int arg;
1523{
1524	icmp->icmp_id = htons(arg);
1525}
1526
1527
1528void set_icmpseq(arg)
1529int arg;
1530{
1531	icmp->icmp_seq = htons(arg);
1532}
1533
1534
1535void set_icmpotime(arg)
1536int arg;
1537{
1538	icmp->icmp_otime = htonl(arg);
1539}
1540
1541
1542void set_icmprtime(arg)
1543int arg;
1544{
1545	icmp->icmp_rtime = htonl(arg);
1546}
1547
1548
1549void set_icmpttime(arg)
1550int arg;
1551{
1552	icmp->icmp_ttime = htonl(arg);
1553}
1554
1555
1556void set_icmpmtu(arg)
1557int arg;
1558{
1559	icmp->icmp_nextmtu = htons(arg);
1560}
1561
1562
1563void set_redir(redir, arg)
1564int redir;
1565char **arg;
1566{
1567	icmp->icmp_code = redir;
1568	icmp->icmp_gwaddr = getipv4addr(*arg);
1569	free(*arg);
1570	*arg = NULL;
1571}
1572
1573
1574void set_icmppprob(num)
1575int num;
1576{
1577	icmp->icmp_pptr = num;
1578}
1579
1580
1581void new_ipv4opt()
1582{
1583	new_header(-2);
1584}
1585
1586
1587void add_ipopt(state, ptr)
1588int state;
1589void *ptr;
1590{
1591	struct ipopt_names *io;
1592	struct statetoopt *sto;
1593	char numbuf[16], *arg, **param = ptr;
1594	int inc, hlen;
1595
1596	if (state == IL_IPO_RR || state == IL_IPO_SATID) {
1597		if (param)
1598			sprintf(numbuf, "%d", *(int *)param);
1599		else
1600			strcpy(numbuf, "0");
1601		arg = numbuf;
1602	} else
1603		arg = param ? *param : NULL;
1604
1605	if (canip->ah_next) {
1606		fprintf(stderr, "cannot specify options after data body\n");
1607		return;
1608	}
1609	for (sto = toipopts; sto->sto_st; sto++)
1610		if (sto->sto_st == state)
1611			break;
1612	if (!sto->sto_st) {
1613		fprintf(stderr, "No mapping for state %d to IP option\n",
1614			state);
1615		return;
1616	}
1617
1618	hlen = sizeof(ip_t) + canip->ah_optlen;
1619	for (io = ionames; io->on_name; io++)
1620		if (io->on_value == sto->sto_op)
1621			break;
1622	canip->ah_lastopt = io->on_value;
1623
1624	if (io->on_name) {
1625		inc = addipopt((char *)ip + hlen, io, hlen - sizeof(ip_t),arg);
1626		if (inc > 0) {
1627			while (inc & 3) {
1628				((char *)ip)[sizeof(*ip) + inc] = IPOPT_NOP;
1629				canip->ah_lastopt = IPOPT_NOP;
1630				inc++;
1631			}
1632			hlen += inc;
1633		}
1634	}
1635
1636	canip->ah_optlen = hlen - sizeof(ip_t);
1637
1638	if (state != IL_IPO_RR && state != IL_IPO_SATID)
1639		if (param && *param) {
1640			free(*param);
1641			*param = NULL;
1642		}
1643	sclass = NULL;
1644}
1645
1646
1647void end_ipopt()
1648{
1649	int pad;
1650	char *s, *buf = (char *)ip;
1651
1652	/*
1653	 * pad out so that we have a multiple of 4 bytes in size fo the
1654	 * options.  make sure last byte is EOL.
1655	 */
1656	if (canip->ah_lastopt == IPOPT_NOP) {
1657		buf[sizeof(*ip) + canip->ah_optlen - 1] = IPOPT_EOL;
1658	} else if (canip->ah_lastopt != IPOPT_EOL) {
1659		s = buf + sizeof(*ip) + canip->ah_optlen;
1660
1661		for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
1662			*s++ = IPOPT_NOP;
1663			*s = IPOPT_EOL;
1664			canip->ah_optlen++;
1665		}
1666		canip->ah_optlen++;
1667	} else {
1668		s = buf + sizeof(*ip) + canip->ah_optlen - 1;
1669
1670		for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
1671			*s++ = IPOPT_NOP;
1672			*s = IPOPT_EOL;
1673			canip->ah_optlen++;
1674		}
1675	}
1676	ip->ip_hl = (sizeof(*ip) + canip->ah_optlen) >> 2;
1677	inc_anipheaders(canip->ah_optlen);
1678	free_anipheader();
1679}
1680
1681
1682void set_secclass(arg)
1683char **arg;
1684{
1685	sclass = *arg;
1686	*arg = NULL;
1687}
1688
1689
1690void free_anipheader()
1691{
1692	aniphdr_t *aip;
1693
1694	aip = canip;
1695	if ((canip = aip->ah_prev)) {
1696		canip->ah_next = NULL;
1697		aniptail = &canip->ah_next;
1698	}
1699
1700	if (canip)
1701		free(aip);
1702}
1703
1704
1705void end_ipv4()
1706{
1707	aniphdr_t *aip;
1708
1709	ip->ip_sum = 0;
1710	ip->ip_len = htons(ip->ip_len);
1711	ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2);
1712	ip->ip_len = ntohs(ip->ip_len);
1713	free_anipheader();
1714	for (aip = aniphead, ip = NULL; aip; aip = aip->ah_next)
1715		if (aip->ah_p == IPPROTO_IP)
1716			ip = aip->ah_ip;
1717}
1718
1719
1720void end_icmp()
1721{
1722	aniphdr_t *aip;
1723
1724	icmp->icmp_cksum = 0;
1725	icmp->icmp_cksum = chksum((u_short *)icmp, canip->ah_len);
1726	free_anipheader();
1727	for (aip = aniphead, icmp = NULL; aip; aip = aip->ah_next)
1728		if (aip->ah_p == IPPROTO_ICMP)
1729			icmp = aip->ah_icmp;
1730}
1731
1732
1733void end_udp()
1734{
1735	u_long	sum;
1736	aniphdr_t *aip;
1737	ip_t	iptmp;
1738
1739	bzero((char *)&iptmp, sizeof(iptmp));
1740	iptmp.ip_p = ip->ip_p;
1741	iptmp.ip_src = ip->ip_src;
1742	iptmp.ip_dst = ip->ip_dst;
1743	iptmp.ip_len = htons(ip->ip_len - (ip->ip_hl << 2));
1744	sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp));
1745	udp->uh_ulen = htons(udp->uh_ulen);
1746	udp->uh_sum = c_chksum((u_short *)udp, (u_int)ntohs(iptmp.ip_len), sum);
1747	free_anipheader();
1748	for (aip = aniphead, udp = NULL; aip; aip = aip->ah_next)
1749		if (aip->ah_p == IPPROTO_UDP)
1750			udp = aip->ah_udp;
1751}
1752
1753
1754void end_tcp()
1755{
1756	u_long	sum;
1757	aniphdr_t *aip;
1758	ip_t	iptmp;
1759
1760	bzero((char *)&iptmp, sizeof(iptmp));
1761	iptmp.ip_p = ip->ip_p;
1762	iptmp.ip_src = ip->ip_src;
1763	iptmp.ip_dst = ip->ip_dst;
1764	iptmp.ip_len = htons(ip->ip_len - (ip->ip_hl << 2));
1765	sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp));
1766	tcp->th_sum = 0;
1767	tcp->th_sum = c_chksum((u_short *)tcp, (u_int)ntohs(iptmp.ip_len), sum);
1768	free_anipheader();
1769	for (aip = aniphead, tcp = NULL; aip; aip = aip->ah_next)
1770		if (aip->ah_p == IPPROTO_TCP)
1771			tcp = aip->ah_tcp;
1772}
1773
1774
1775void end_data()
1776{
1777	free_anipheader();
1778}
1779
1780
1781void iplang(fp)
1782FILE *fp;
1783{
1784	yyin = fp;
1785
1786	yydebug = (opts & OPT_DEBUG) ? 1 : 0;
1787
1788	while (!feof(fp))
1789		yyparse();
1790}
1791
1792
1793u_short	c_chksum(buf, len, init)
1794u_short	*buf;
1795u_int	len;
1796u_long	init;
1797{
1798	u_long	sum = init;
1799	int	nwords = len >> 1;
1800
1801	for(; nwords > 0; nwords--)
1802		sum += *buf++;
1803	sum = (sum>>16) + (sum & 0xffff);
1804	sum += (sum >>16);
1805	return (~sum);
1806}
1807
1808
1809u_long	p_chksum(buf,len)
1810u_short	*buf;
1811u_int	len;
1812{
1813	u_long	sum = 0;
1814	int	nwords = len >> 1;
1815
1816	for(; nwords > 0; nwords--)
1817		sum += *buf++;
1818	return sum;
1819}
1820