1*76404edcSAsim Jamshed #define _LARGEFILE64_SOURCE
2*76404edcSAsim Jamshed #include <stdio.h>
3*76404edcSAsim Jamshed #include <stdlib.h>
4*76404edcSAsim Jamshed #include <unistd.h>
5*76404edcSAsim Jamshed #include <stdint.h>
6*76404edcSAsim Jamshed #include <sys/types.h>
7*76404edcSAsim Jamshed #include <sys/stat.h>
8*76404edcSAsim Jamshed #include <sys/socket.h>
9*76404edcSAsim Jamshed #include <netinet/in.h>
10*76404edcSAsim Jamshed #include <arpa/inet.h>
11*76404edcSAsim Jamshed #include <fcntl.h>
12*76404edcSAsim Jamshed #include <dirent.h>
13*76404edcSAsim Jamshed #include <string.h>
14*76404edcSAsim Jamshed #include <time.h>
15*76404edcSAsim Jamshed #include <pthread.h>
16*76404edcSAsim Jamshed #include <signal.h>
17*76404edcSAsim Jamshed #include <linux/if_ether.h>
18*76404edcSAsim Jamshed #include <linux/tcp.h>
19*76404edcSAsim Jamshed #include <mos_api.h>
20*76404edcSAsim Jamshed #include <ctype.h>
21*76404edcSAsim Jamshed #include "cpu.h"
22*76404edcSAsim Jamshed #include "http_parsing.h"
23*76404edcSAsim Jamshed #include "debug.h"
24*76404edcSAsim Jamshed #include "applib.h"
25*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
26*76404edcSAsim Jamshed /* default configuration file path */
27*76404edcSAsim Jamshed #define MOS_CONFIG_FILE		     "config/mos.conf"
28*76404edcSAsim Jamshed /* max length per line in firewall config file */
29*76404edcSAsim Jamshed #define CONF_MAX_LINE_LEN        1024
30*76404edcSAsim Jamshed /* number of array elements */
31*76404edcSAsim Jamshed #define NELEMS(x)           (sizeof(x) / sizeof(x[0]))
32*76404edcSAsim Jamshed /* macro to skip spaces */
33*76404edcSAsim Jamshed #define SKIP_SPACES(x) while (*x && isspace((int)*x)) x++;
34*76404edcSAsim Jamshed /* macro to skip characters */
35*76404edcSAsim Jamshed #define SKIP_CHAR(x) while((*x) && !isspace(*x)) x++;
36*76404edcSAsim Jamshed /* macro to skip digit characters */
37*76404edcSAsim Jamshed #define SKIP_DIGIT(x) while((*x) && isdigit(*x)) x++;
38*76404edcSAsim Jamshed /* macro to do netmasking with ip address */
39*76404edcSAsim Jamshed #define IP_NETMASK(x, y) x & (0xFFFFFFFF >> (32 - y));
40*76404edcSAsim Jamshed /* macro to dump error and exit */
41*76404edcSAsim Jamshed #define EXIT_WITH_ERROR(f, m...) {                                 \
42*76404edcSAsim Jamshed 		fprintf(stderr, "[%10s:%4d] errno: %u" f, __FUNCTION__, __LINE__, errno, ##m); \
43*76404edcSAsim Jamshed 	exit(EXIT_FAILURE);                                            \
44*76404edcSAsim Jamshed }
45*76404edcSAsim Jamshed /* boolean for function return value */
46*76404edcSAsim Jamshed #define SUCCESS 1
47*76404edcSAsim Jamshed #define FAILURE 0
48*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
49*76404edcSAsim Jamshed /* firewall rule action */
50*76404edcSAsim Jamshed typedef enum {FRA_INVALID, FRA_ACCEPT, FRA_DROP} FRAction;
51*76404edcSAsim Jamshed #define FR_ACCEPT "ACCEPT"
52*76404edcSAsim Jamshed #define FR_DROP   "DROP"
53*76404edcSAsim Jamshed #define FR_SPORT  "sport:"
54*76404edcSAsim Jamshed #define FR_DPORT  "dport:"
55*76404edcSAsim Jamshed /* firewall rule structure */
56*76404edcSAsim Jamshed #define MAX_RULES 1024
57*76404edcSAsim Jamshed #define MAX_IP_ADDR_LEN 19      /* in CIDR format */
58*76404edcSAsim Jamshed /* all fields are in network byte order */
59*76404edcSAsim Jamshed typedef struct FirewallRule {
60*76404edcSAsim Jamshed 	in_addr_t fr_srcIP;         /* source IP */
61*76404edcSAsim Jamshed 	int       fr_srcIPmask;     /* source IP netmask */
62*76404edcSAsim Jamshed 	in_addr_t fr_dstIP;         /* destination IP */
63*76404edcSAsim Jamshed 	int       fr_dstIPmask;     /* destination IP netmask */
64*76404edcSAsim Jamshed 	in_port_t fr_srcPort;       /* source port */
65*76404edcSAsim Jamshed 	in_port_t fr_dstPort;       /* destination port */
66*76404edcSAsim Jamshed 	FRAction  fr_action;        /* action */
67*76404edcSAsim Jamshed 	uint32_t  fr_count;         /* packet count */
68*76404edcSAsim Jamshed } FirewallRule;
69*76404edcSAsim Jamshed static FirewallRule g_FWRules[MAX_RULES];
70*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
71*76404edcSAsim Jamshed struct thread_context
72*76404edcSAsim Jamshed {
73*76404edcSAsim Jamshed 	mctx_t mctx;         /* per-thread mos context */
74*76404edcSAsim Jamshed 	int mon_listener;    /* listening socket for flow monitoring */
75*76404edcSAsim Jamshed };
76*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
77*76404edcSAsim Jamshed /* Print the entire firewall rule and status table */
78*76404edcSAsim Jamshed static void
DumpFWRuleTable(mctx_t mctx,int sock,int side,uint64_t events,filter_arg_t * arg)79*76404edcSAsim Jamshed DumpFWRuleTable(mctx_t mctx, int sock, int side,
80*76404edcSAsim Jamshed 		uint64_t events, filter_arg_t *arg)
81*76404edcSAsim Jamshed {
82*76404edcSAsim Jamshed 	int i;
83*76404edcSAsim Jamshed   	FirewallRule *fwr;
84*76404edcSAsim Jamshed 	char cip_str[MAX_IP_ADDR_LEN];
85*76404edcSAsim Jamshed 	char sip_str[MAX_IP_ADDR_LEN];
86*76404edcSAsim Jamshed 	struct timeval tv_1sec = { /* 1 second */
87*76404edcSAsim Jamshed 		.tv_sec = 1,
88*76404edcSAsim Jamshed 		.tv_usec = 0
89*76404edcSAsim Jamshed 	};
90*76404edcSAsim Jamshed 
91*76404edcSAsim Jamshed 	printf("-----------------------------------------------------------------------\n");
92*76404edcSAsim Jamshed 	printf("Firewall rule table\n");
93*76404edcSAsim Jamshed 	printf("idx   flows   target   client             server             port\n");
94*76404edcSAsim Jamshed 
95*76404edcSAsim Jamshed 	for (i = 0;  i < MAX_RULES; i++) {
96*76404edcSAsim Jamshed 		fwr = &g_FWRules[i];
97*76404edcSAsim Jamshed 
98*76404edcSAsim Jamshed 		/* we've searched till the end */
99*76404edcSAsim Jamshed 		if (fwr->fr_action == FRA_INVALID)
100*76404edcSAsim Jamshed 			break;
101*76404edcSAsim Jamshed 
102*76404edcSAsim Jamshed 		/* print out each rule */
103*76404edcSAsim Jamshed 		if (!inet_ntop(AF_INET, &(fwr->fr_srcIP), cip_str, INET_ADDRSTRLEN) ||
104*76404edcSAsim Jamshed 			!inet_ntop(AF_INET, &(fwr->fr_dstIP), sip_str, INET_ADDRSTRLEN))
105*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("inet_ntop() error\n");
106*76404edcSAsim Jamshed 
107*76404edcSAsim Jamshed 		if (fwr->fr_srcIPmask != 32)
108*76404edcSAsim Jamshed 			sprintf(cip_str, "%s/%d", cip_str, fwr->fr_srcIPmask);
109*76404edcSAsim Jamshed 		if (fwr->fr_dstIPmask != 32)
110*76404edcSAsim Jamshed 			sprintf(sip_str, "%s/%d", sip_str, fwr->fr_dstIPmask);
111*76404edcSAsim Jamshed 		printf("%-6u%-8u%-9s%-19s%-19s",
112*76404edcSAsim Jamshed 			   (i + 1), fwr->fr_count,
113*76404edcSAsim Jamshed 			   (fwr->fr_action == FRA_DROP)? FR_DROP : FR_ACCEPT,
114*76404edcSAsim Jamshed 			   cip_str, sip_str);
115*76404edcSAsim Jamshed 		if (fwr->fr_srcPort)
116*76404edcSAsim Jamshed 			printf("sport:%-6d", ntohs(fwr->fr_srcPort));
117*76404edcSAsim Jamshed 		if (fwr->fr_dstPort)
118*76404edcSAsim Jamshed 			printf("dport:%-6d", ntohs(fwr->fr_dstPort));
119*76404edcSAsim Jamshed 		printf("\n");
120*76404edcSAsim Jamshed 	}
121*76404edcSAsim Jamshed 	printf("-----------------------------------------------------------------------\n");
122*76404edcSAsim Jamshed 
123*76404edcSAsim Jamshed 	/* Set a timer for next printing */
124*76404edcSAsim Jamshed 	if (mtcp_settimer(mctx, sock, &tv_1sec, DumpFWRuleTable))
125*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("mtcp_settimer() error\n");
126*76404edcSAsim Jamshed }
127*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
128*76404edcSAsim Jamshed static inline char*
ExtractPort(char * buf,in_port_t * sport,in_port_t * dport)129*76404edcSAsim Jamshed ExtractPort(char* buf, in_port_t* sport, in_port_t* dport)
130*76404edcSAsim Jamshed {
131*76404edcSAsim Jamshed 	in_port_t* p = NULL;
132*76404edcSAsim Jamshed 	char* temp = (char*)buf;
133*76404edcSAsim Jamshed 	char* check;
134*76404edcSAsim Jamshed 	int port;
135*76404edcSAsim Jamshed 	char s = 0;             /* swap character */
136*76404edcSAsim Jamshed 
137*76404edcSAsim Jamshed 	SKIP_CHAR(temp);	    /* skip characters */
138*76404edcSAsim Jamshed 	s = *temp; *temp = 0;	/* replace the end character with null */
139*76404edcSAsim Jamshed 
140*76404edcSAsim Jamshed 	/* check if the port format is correct */
141*76404edcSAsim Jamshed 	if (!strncmp(buf, FR_SPORT, sizeof(FR_SPORT) - 1)) {
142*76404edcSAsim Jamshed 		p = sport;
143*76404edcSAsim Jamshed 		buf += (sizeof(FR_SPORT) - 1);
144*76404edcSAsim Jamshed 	}
145*76404edcSAsim Jamshed 	else if (!strncmp(buf, FR_DPORT, sizeof(FR_DPORT) - 1)) {
146*76404edcSAsim Jamshed 		p = dport;
147*76404edcSAsim Jamshed 		buf += (sizeof(FR_DPORT) - 1);
148*76404edcSAsim Jamshed 	}
149*76404edcSAsim Jamshed 	else
150*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Invalid rule in port setup [%s]\n", buf);
151*76404edcSAsim Jamshed 
152*76404edcSAsim Jamshed 	check = buf;
153*76404edcSAsim Jamshed 	SKIP_DIGIT(check);
154*76404edcSAsim Jamshed 	if (check != temp)
155*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Invalid port format [%s]\n", buf);
156*76404edcSAsim Jamshed 
157*76404edcSAsim Jamshed 	/* convert to port number */
158*76404edcSAsim Jamshed 	port = atoi(buf);
159*76404edcSAsim Jamshed 	if (port < 0 || port > 65536)
160*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Invalid port [%d]\n", port);
161*76404edcSAsim Jamshed 	(*p) = htons(port);
162*76404edcSAsim Jamshed 
163*76404edcSAsim Jamshed 	(*temp) = s;	/* recover the original character */
164*76404edcSAsim Jamshed 	buf = temp;	    /* move buf pointer to next string */
165*76404edcSAsim Jamshed 	SKIP_SPACES(buf);
166*76404edcSAsim Jamshed 
167*76404edcSAsim Jamshed 	return buf;
168*76404edcSAsim Jamshed }
169*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
170*76404edcSAsim Jamshed static inline char*
ExtractIPAddress(char * buf,in_addr_t * addr,int * addrmask)171*76404edcSAsim Jamshed ExtractIPAddress(char* buf, in_addr_t* addr, int* addrmask)
172*76404edcSAsim Jamshed {
173*76404edcSAsim Jamshed 	struct in_addr addr_conv;
174*76404edcSAsim Jamshed 	char* temp = (char*)buf;
175*76404edcSAsim Jamshed 	char* check;
176*76404edcSAsim Jamshed 	int netmask = 32;
177*76404edcSAsim Jamshed 	char s = 0;        /* swap character */
178*76404edcSAsim Jamshed 
179*76404edcSAsim Jamshed 	/* skip characters which are not '/' */
180*76404edcSAsim Jamshed 	while ((*temp) && !isspace(*temp) && (*temp) != '/') temp++;
181*76404edcSAsim Jamshed 
182*76404edcSAsim Jamshed 	s = *temp; *temp = 0;
183*76404edcSAsim Jamshed 	if (inet_aton(buf, &addr_conv) == 0)
184*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Invalid IP address [%s]\n", buf);
185*76404edcSAsim Jamshed 	(*addr) = addr_conv.s_addr;
186*76404edcSAsim Jamshed 	(*temp) = s;
187*76404edcSAsim Jamshed 
188*76404edcSAsim Jamshed 	/* if the rule contains netmask */
189*76404edcSAsim Jamshed 	if ((*temp) == '/') {
190*76404edcSAsim Jamshed 		buf = temp + 1;
191*76404edcSAsim Jamshed 		SKIP_CHAR(temp);
192*76404edcSAsim Jamshed 		s = *temp; *temp = 0;
193*76404edcSAsim Jamshed 
194*76404edcSAsim Jamshed 		/* check if the format is correct */
195*76404edcSAsim Jamshed 		check = buf;
196*76404edcSAsim Jamshed 		SKIP_DIGIT(check);
197*76404edcSAsim Jamshed 		if (check != temp)
198*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Invalid netmask format [%s]\n", buf);
199*76404edcSAsim Jamshed 
200*76404edcSAsim Jamshed 		/* convert to netmask number */
201*76404edcSAsim Jamshed 		netmask = atoi(buf);
202*76404edcSAsim Jamshed 		if (netmask < 0 || netmask > 32)
203*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Invalid netmask [%s]\n", buf);
204*76404edcSAsim Jamshed 		(*addr) = IP_NETMASK((*addr), netmask);
205*76404edcSAsim Jamshed 		(*temp) = s;
206*76404edcSAsim Jamshed 	}
207*76404edcSAsim Jamshed 
208*76404edcSAsim Jamshed 	/* move buf pointer to next string */
209*76404edcSAsim Jamshed 	buf = temp;
210*76404edcSAsim Jamshed 	SKIP_SPACES(buf);
211*76404edcSAsim Jamshed 
212*76404edcSAsim Jamshed 	(*addrmask) = netmask;
213*76404edcSAsim Jamshed 
214*76404edcSAsim Jamshed 	return buf;
215*76404edcSAsim Jamshed }
216*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
217*76404edcSAsim Jamshed static void
ParseConfigFile(char * configF)218*76404edcSAsim Jamshed ParseConfigFile(char* configF)
219*76404edcSAsim Jamshed {
220*76404edcSAsim Jamshed   	FirewallRule *fwr;
221*76404edcSAsim Jamshed 	FILE *fp;
222*76404edcSAsim Jamshed 	char line_buf[CONF_MAX_LINE_LEN] = {0};
223*76404edcSAsim Jamshed 	char *line, *p;
224*76404edcSAsim Jamshed 	int i = 0;
225*76404edcSAsim Jamshed 
226*76404edcSAsim Jamshed 	/* config file path should not be null */
227*76404edcSAsim Jamshed 	assert(configF != NULL);
228*76404edcSAsim Jamshed 
229*76404edcSAsim Jamshed 	/* open firewall rule file */
230*76404edcSAsim Jamshed 	if ((fp = fopen(configF, "r")) == NULL)
231*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Firewall rule file %s is not found.\n", configF);
232*76404edcSAsim Jamshed 
233*76404edcSAsim Jamshed 	/* read each line */
234*76404edcSAsim Jamshed 	while ((line = fgets(line_buf, CONF_MAX_LINE_LEN, fp)) != NULL) {
235*76404edcSAsim Jamshed 
236*76404edcSAsim Jamshed 		/* each line represents a rule */
237*76404edcSAsim Jamshed 		fwr = &g_FWRules[i];
238*76404edcSAsim Jamshed 		if (line[CONF_MAX_LINE_LEN - 1])
239*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("%s has a line longer than %d\n",
240*76404edcSAsim Jamshed 						configF, CONF_MAX_LINE_LEN);
241*76404edcSAsim Jamshed 
242*76404edcSAsim Jamshed 		SKIP_SPACES(line); /* remove spaces */
243*76404edcSAsim Jamshed 		if (*line == '\0' || *line == '#')
244*76404edcSAsim Jamshed 			continue;
245*76404edcSAsim Jamshed 		if ((p = strchr(line, '#'))) /* skip comments in the line */
246*76404edcSAsim Jamshed 			*p = '\0';
247*76404edcSAsim Jamshed 		while (isspace(line[strlen(line) - 1])) /* remove spaces */
248*76404edcSAsim Jamshed 			line[strlen(line) - 1] = '\0';
249*76404edcSAsim Jamshed 
250*76404edcSAsim Jamshed 		/* read firewall rule action */
251*76404edcSAsim Jamshed 		p = line;
252*76404edcSAsim Jamshed 		if (!strncmp(p, FR_ACCEPT, sizeof(FR_ACCEPT) - 1)) {
253*76404edcSAsim Jamshed 			fwr->fr_action = FRA_ACCEPT;
254*76404edcSAsim Jamshed 			p += (sizeof(FR_ACCEPT) - 1);
255*76404edcSAsim Jamshed 		}
256*76404edcSAsim Jamshed 		else if (!strncmp(p, FR_DROP, sizeof(FR_DROP) - 1)) {
257*76404edcSAsim Jamshed 			fwr->fr_action = FRA_DROP;
258*76404edcSAsim Jamshed 			p += (sizeof(FR_DROP) - 1);
259*76404edcSAsim Jamshed 		}
260*76404edcSAsim Jamshed 		else
261*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Unknown rule action [%s].\n", line);
262*76404edcSAsim Jamshed 
263*76404edcSAsim Jamshed 		if (!isspace(*p)) /* invalid if no space exists after action */
264*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Invalid format [%s].\n", line);
265*76404edcSAsim Jamshed 		SKIP_SPACES(p);
266*76404edcSAsim Jamshed 
267*76404edcSAsim Jamshed 		/* read client ip address */
268*76404edcSAsim Jamshed 		if (*p)
269*76404edcSAsim Jamshed 			p = ExtractIPAddress(p, &fwr->fr_srcIP, &(fwr->fr_srcIPmask));
270*76404edcSAsim Jamshed 		else
271*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Invalid format [%s].\n", line);
272*76404edcSAsim Jamshed 
273*76404edcSAsim Jamshed 		/* read server ip address */
274*76404edcSAsim Jamshed 		if (*p)
275*76404edcSAsim Jamshed 			p = ExtractIPAddress(p, &fwr->fr_dstIP, &(fwr->fr_dstIPmask));
276*76404edcSAsim Jamshed 		else
277*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Invalid format [%s].\n", line);
278*76404edcSAsim Jamshed 
279*76404edcSAsim Jamshed 		/* read port filter information */
280*76404edcSAsim Jamshed 		while (*p)
281*76404edcSAsim Jamshed 			p = ExtractPort(p, &(fwr->fr_srcPort), &(fwr->fr_dstPort));
282*76404edcSAsim Jamshed 
283*76404edcSAsim Jamshed 		fwr->fr_count = 0;
284*76404edcSAsim Jamshed 		if ((i++) >= MAX_RULES)
285*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Exceeded max number of rules (%d)\n", MAX_RULES);
286*76404edcSAsim Jamshed 	}
287*76404edcSAsim Jamshed 
288*76404edcSAsim Jamshed 	fclose(fp);
289*76404edcSAsim Jamshed }
290*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
291*76404edcSAsim Jamshed static inline int
MatchAddr(in_addr_t ip,in_addr_t fw_ip,int netmask)292*76404edcSAsim Jamshed MatchAddr(in_addr_t ip, in_addr_t fw_ip, int netmask)
293*76404edcSAsim Jamshed {
294*76404edcSAsim Jamshed 	ip = IP_NETMASK(ip, netmask);
295*76404edcSAsim Jamshed 
296*76404edcSAsim Jamshed 	/* 0 means '*' */
297*76404edcSAsim Jamshed 	return (fw_ip == 0 || ip == fw_ip);
298*76404edcSAsim Jamshed }
299*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
300*76404edcSAsim Jamshed static inline int
MatchPort(in_port_t port,in_port_t fw_port)301*76404edcSAsim Jamshed MatchPort(in_port_t port, in_port_t fw_port)
302*76404edcSAsim Jamshed {
303*76404edcSAsim Jamshed 	/* 0 means '*' */
304*76404edcSAsim Jamshed 	return (fw_port == 0 || port == fw_port);
305*76404edcSAsim Jamshed }
306*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
307*76404edcSAsim Jamshed static int
FWRLookup(in_addr_t sip,in_addr_t dip,in_port_t sp,in_port_t dp)308*76404edcSAsim Jamshed FWRLookup(in_addr_t sip, in_addr_t dip, in_port_t sp, in_port_t dp)
309*76404edcSAsim Jamshed {
310*76404edcSAsim Jamshed 	int i;
311*76404edcSAsim Jamshed 	FirewallRule *p = g_FWRules;
312*76404edcSAsim Jamshed 
313*76404edcSAsim Jamshed 	for (i = 0;  i < MAX_RULES; i++) {
314*76404edcSAsim Jamshed 		if (p[i].fr_action == FRA_INVALID) {
315*76404edcSAsim Jamshed 			/* We've searched till the end. By default, allow any flow */
316*76404edcSAsim Jamshed 			return (FRA_ACCEPT);
317*76404edcSAsim Jamshed 		}
318*76404edcSAsim Jamshed 
319*76404edcSAsim Jamshed 		if (MatchAddr(sip, p[i].fr_srcIP, p[i].fr_srcIPmask) &&
320*76404edcSAsim Jamshed 			MatchAddr(dip, p[i].fr_dstIP, p[i].fr_dstIPmask) &&
321*76404edcSAsim Jamshed 			MatchPort(sp, p[i].fr_srcPort) &&
322*76404edcSAsim Jamshed 			MatchPort(dp, p[i].fr_dstPort)) {
323*76404edcSAsim Jamshed 			p[i].fr_count++;
324*76404edcSAsim Jamshed 			return p[i].fr_action;
325*76404edcSAsim Jamshed 		}
326*76404edcSAsim Jamshed 	}
327*76404edcSAsim Jamshed 
328*76404edcSAsim Jamshed 	assert(0); /* can't reach here */
329*76404edcSAsim Jamshed 	return  (FRA_ACCEPT);
330*76404edcSAsim Jamshed }
331*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
332*76404edcSAsim Jamshed static void
ApplyActionPerFlow(mctx_t mctx,int msock,int side,uint64_t events,filter_arg_t * arg)333*76404edcSAsim Jamshed ApplyActionPerFlow(mctx_t mctx, int msock, int side,
334*76404edcSAsim Jamshed 		   		     uint64_t events, filter_arg_t *arg)
335*76404edcSAsim Jamshed 
336*76404edcSAsim Jamshed {
337*76404edcSAsim Jamshed 	/* this function is called at the first SYN */
338*76404edcSAsim Jamshed 	struct pkt_info p;
339*76404edcSAsim Jamshed 	int opt;
340*76404edcSAsim Jamshed 	FRAction action;
341*76404edcSAsim Jamshed 
342*76404edcSAsim Jamshed 	if (mtcp_getlastpkt(mctx, msock, side, &p) < 0)
343*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Failed to get packet context!\n");
344*76404edcSAsim Jamshed 
345*76404edcSAsim Jamshed 	/* look up the firewall rules */
346*76404edcSAsim Jamshed 	action = FWRLookup(p.iph->saddr, p.iph->daddr,
347*76404edcSAsim Jamshed 					    p.tcph->source, p.tcph->dest);
348*76404edcSAsim Jamshed 
349*76404edcSAsim Jamshed 	if (action == FRA_DROP) {
350*76404edcSAsim Jamshed 		mtcp_setlastpkt(mctx, msock, side, 0, NULL, 0, MOS_DROP);
351*76404edcSAsim Jamshed 	} else {
352*76404edcSAsim Jamshed 		assert(action == FRA_ACCEPT);
353*76404edcSAsim Jamshed 		/* no need to monitor this flow any more */
354*76404edcSAsim Jamshed 		opt = MOS_SIDE_BOTH;
355*76404edcSAsim Jamshed 		if (mtcp_setsockopt(mctx, msock, SOL_MONSOCKET,
356*76404edcSAsim Jamshed 				    MOS_STOP_MON, &opt, sizeof(opt)) < 0)
357*76404edcSAsim Jamshed 			EXIT_WITH_ERROR("Failed to stop monitoring conn with sockid: %d\n",
358*76404edcSAsim Jamshed 					msock);
359*76404edcSAsim Jamshed 	}
360*76404edcSAsim Jamshed }
361*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
362*76404edcSAsim Jamshed static bool
CatchInitSYN(mctx_t mctx,int sockid,int side,uint64_t events,filter_arg_t * arg)363*76404edcSAsim Jamshed CatchInitSYN(mctx_t mctx, int sockid,
364*76404edcSAsim Jamshed 			int side, uint64_t events, filter_arg_t *arg)
365*76404edcSAsim Jamshed {
366*76404edcSAsim Jamshed 	struct pkt_info p;
367*76404edcSAsim Jamshed 
368*76404edcSAsim Jamshed 	if (mtcp_getlastpkt(mctx, sockid, side, &p) < 0)
369*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Failed to get packet context!!!\n");
370*76404edcSAsim Jamshed 
371*76404edcSAsim Jamshed 	return (p.tcph->syn && !p.tcph->ack);
372*76404edcSAsim Jamshed }
373*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
374*76404edcSAsim Jamshed static void
CreateAndInitThreadContext(struct thread_context * ctx,int core,event_t udeForSYN)375*76404edcSAsim Jamshed CreateAndInitThreadContext(struct thread_context* ctx,
376*76404edcSAsim Jamshed 						      int core, event_t  udeForSYN)
377*76404edcSAsim Jamshed {
378*76404edcSAsim Jamshed 	struct timeval tv_1sec = { /* 1 second */
379*76404edcSAsim Jamshed 		.tv_sec = 1,
380*76404edcSAsim Jamshed 		.tv_usec = 0
381*76404edcSAsim Jamshed 	};
382*76404edcSAsim Jamshed 
383*76404edcSAsim Jamshed 	ctx->mctx = mtcp_create_context(core);
384*76404edcSAsim Jamshed 
385*76404edcSAsim Jamshed 	/* create socket  */
386*76404edcSAsim Jamshed 	ctx->mon_listener = mtcp_socket(ctx->mctx, AF_INET,
387*76404edcSAsim Jamshed 					MOS_SOCK_MONITOR_STREAM, 0);
388*76404edcSAsim Jamshed 	if (ctx->mon_listener < 0)
389*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Failed to create monitor listening socket!\n");
390*76404edcSAsim Jamshed 
391*76404edcSAsim Jamshed 	/* register callback */
392*76404edcSAsim Jamshed 	if (mtcp_register_callback(ctx->mctx, ctx->mon_listener,
393*76404edcSAsim Jamshed 							   udeForSYN,
394*76404edcSAsim Jamshed 							   MOS_HK_SND,
395*76404edcSAsim Jamshed 				   			   ApplyActionPerFlow) == -1)
396*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Failed to register callback func!\n");
397*76404edcSAsim Jamshed 
398*76404edcSAsim Jamshed 	/* CPU 0 is in charge of printing stats */
399*76404edcSAsim Jamshed 	if (ctx->mctx->cpu == 0 &&
400*76404edcSAsim Jamshed 		mtcp_settimer(ctx->mctx, ctx->mon_listener,
401*76404edcSAsim Jamshed 					  &tv_1sec, DumpFWRuleTable))
402*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Failed to register timer callback func!\n");
403*76404edcSAsim Jamshed 
404*76404edcSAsim Jamshed }
405*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
406*76404edcSAsim Jamshed static void
WaitAndCleanupThreadContext(struct thread_context * ctx)407*76404edcSAsim Jamshed WaitAndCleanupThreadContext(struct thread_context* ctx)
408*76404edcSAsim Jamshed {
409*76404edcSAsim Jamshed 	/* wait for the TCP thread to finish */
410*76404edcSAsim Jamshed 	mtcp_app_join(ctx->mctx);
411*76404edcSAsim Jamshed 
412*76404edcSAsim Jamshed 	/* close the monitoring socket */
413*76404edcSAsim Jamshed 	mtcp_close(ctx->mctx, ctx->mon_listener);
414*76404edcSAsim Jamshed 
415*76404edcSAsim Jamshed 	/* tear down */
416*76404edcSAsim Jamshed 	mtcp_destroy_context(ctx->mctx);
417*76404edcSAsim Jamshed }
418*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
419*76404edcSAsim Jamshed int
main(int argc,char ** argv)420*76404edcSAsim Jamshed main(int argc, char **argv)
421*76404edcSAsim Jamshed {
422*76404edcSAsim Jamshed 	int ret, i;
423*76404edcSAsim Jamshed 	char *fname = MOS_CONFIG_FILE; /* path to the default mos config file */
424*76404edcSAsim Jamshed 	struct mtcp_conf mcfg;
425*76404edcSAsim Jamshed 	char simple_firewall_file[1024] = "config/simple_firewall.conf";
426*76404edcSAsim Jamshed 	struct thread_context ctx[MAX_CPUS] = {{0}}; /* init all fields to 0 */
427*76404edcSAsim Jamshed 	event_t initSYNEvent;
428*76404edcSAsim Jamshed 	int num_cpus;
429*76404edcSAsim Jamshed 	int opt, rc;
430*76404edcSAsim Jamshed 
431*76404edcSAsim Jamshed 	/* get the total # of cpu cores */
432*76404edcSAsim Jamshed 	num_cpus = GetNumCPUs();
433*76404edcSAsim Jamshed 
434*76404edcSAsim Jamshed 	while ((opt = getopt(argc, argv, "c:f:n:")) != -1) {
435*76404edcSAsim Jamshed 		switch (opt) {
436*76404edcSAsim Jamshed 			case 'c':
437*76404edcSAsim Jamshed 				fname = optarg;
438*76404edcSAsim Jamshed 				break;
439*76404edcSAsim Jamshed 		        case 'f':
440*76404edcSAsim Jamshed 				strcpy(simple_firewall_file, optarg);
441*76404edcSAsim Jamshed 				break;
442*76404edcSAsim Jamshed 			case 'n':
443*76404edcSAsim Jamshed 				if ((rc=atoi(optarg)) > num_cpus) {
444*76404edcSAsim Jamshed 					EXIT_WITH_ERROR("Available number of CPU cores is %d "
445*76404edcSAsim Jamshed 							"while requested cores is %d\n",
446*76404edcSAsim Jamshed 							num_cpus, rc);
447*76404edcSAsim Jamshed 				}
448*76404edcSAsim Jamshed 				num_cpus = rc;
449*76404edcSAsim Jamshed 				break;
450*76404edcSAsim Jamshed 			default:
451*76404edcSAsim Jamshed 				printf("Usage: %s [-c mos_config_file] "
452*76404edcSAsim Jamshed 				       "[-f simple_firewall_config_file]\n",
453*76404edcSAsim Jamshed 				       argv[0]);
454*76404edcSAsim Jamshed 				return 0;
455*76404edcSAsim Jamshed 		}
456*76404edcSAsim Jamshed 	}
457*76404edcSAsim Jamshed 
458*76404edcSAsim Jamshed 	/* parse mos configuration file */
459*76404edcSAsim Jamshed 	ret = mtcp_init(fname);
460*76404edcSAsim Jamshed 	if (ret)
461*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("Failed to initialize mtcp.\n");
462*76404edcSAsim Jamshed 
463*76404edcSAsim Jamshed 	/* set the core limit */
464*76404edcSAsim Jamshed 	mtcp_getconf(&mcfg);
465*76404edcSAsim Jamshed 	mcfg.num_cores = num_cpus;
466*76404edcSAsim Jamshed 	mtcp_setconf(&mcfg);
467*76404edcSAsim Jamshed 
468*76404edcSAsim Jamshed 	/* parse simple firewall-specfic startup file */
469*76404edcSAsim Jamshed 	ParseConfigFile(simple_firewall_file);
470*76404edcSAsim Jamshed 
471*76404edcSAsim Jamshed 	/* populate local mos-specific mcfg struct for later usage */
472*76404edcSAsim Jamshed 	mtcp_getconf(&mcfg);
473*76404edcSAsim Jamshed 
474*76404edcSAsim Jamshed 	/* event for the initial SYN packet */
475*76404edcSAsim Jamshed 	initSYNEvent = mtcp_define_event(MOS_ON_PKT_IN, CatchInitSYN, NULL);
476*76404edcSAsim Jamshed 	if (initSYNEvent == MOS_NULL_EVENT)
477*76404edcSAsim Jamshed 		EXIT_WITH_ERROR("mtcp_define_event() failed!");
478*76404edcSAsim Jamshed 
479*76404edcSAsim Jamshed 	/* initialize monitor threads */
480*76404edcSAsim Jamshed 	for (i = 0; i < mcfg.num_cores; i++)
481*76404edcSAsim Jamshed 		CreateAndInitThreadContext(&ctx[i], i, initSYNEvent);
482*76404edcSAsim Jamshed 
483*76404edcSAsim Jamshed 	/* wait until all threads finish */
484*76404edcSAsim Jamshed 	for (i = 0; i < mcfg.num_cores; i++) {
485*76404edcSAsim Jamshed 		WaitAndCleanupThreadContext(&ctx[i]);
486*76404edcSAsim Jamshed 	  	TRACE_INFO("Message test thread %d joined.\n", i);
487*76404edcSAsim Jamshed 	}
488*76404edcSAsim Jamshed 
489*76404edcSAsim Jamshed 	mtcp_destroy();
490*76404edcSAsim Jamshed 
491*76404edcSAsim Jamshed 	return EXIT_SUCCESS;
492*76404edcSAsim Jamshed }
493*76404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
494