1/*
2#-------------------------------------------------------------------------------
3#
4# $Id: netstat-nat.c,v 1.33 2010/01/09 19:34:24 danny Exp $
5#
6# $Log: netstat-nat.c,v $
7# Revision 1.33  2010/01/09 19:34:24  danny
8# fix for properly display DNAT over SNAT connection
9#
10# Revision 1.32  2007/11/24 13:18:48  danny
11# - Added '-R' option to show routed connections instead of showing them with '-L'
12# - Some allocation & free bugs were squashed
13#
14# Revision 1.31  2007/05/26 11:48:08  danny
15# Added 'nf_conntrack' support
16# Added NAT host connection information (Used IP and port for NAT)
17#
18# Revision 1.30  2006/08/17 17:43:25  danny
19# - fix for read-in (ip_conntrack), previous versions could sometimes hang or
20#   segfault on some systems.
21# - fix for displaying dnat over snat connections.
22# - changed my email to danny@tweegy.nl and changed homepage url
23#
24# Revision 1.29  2005/07/20 19:50:43  mardan
25# gcc 2.96 compatability fix
26# enlarged readin of ip_conntrack line
27#
28# Revision 1.28  2005/01/29 15:24:37  mardan
29# Some cleanups, bumped to version 1.4.5
30#
31# Revision 1.27  2005/01/23 16:33:09  mardan
32# Added protocol resolving
33#
34# Revision 1.26  2005/01/21 22:54:14  mardan
35# Added some forgotten states
36#
37# Revision 1.25  2005/01/01 17:02:24  mardan
38# Extraction of IPs and ports more dynamicly so it can be used with layer7 and
39# maybe others when layout of ip_conntrack changes
40# Added autoconf
41#
42# Revision 1.24  2003/09/01 20:36:52  mardan
43# Fixed small bug which didn't allow to display hostnames in expanded mode,
44# not enough bytes where allocated.
45#
46# Revision 1.23  2003/08/31 10:59:15  mardan
47# Merged patch from Guomundur D. Haraldsson <gdh@binhex.EU.org> which does a
48# more properly memory alloction and saver copies of variables.
49# Changed versions to v1.4.3. Ready to release if found stable.
50# Changed my e-mail to danny@tweegy.demon.nl
51#
52# Revision 1.22  2003/02/08 17:41:44  mardan
53# made some last minor changes.
54# ready to release v1.4.2
55#
56# Revision 1.21  2003/01/24 21:24:34  mardan
57# Added unknown protocol, display as 'raw'
58# Fixed hussle up in states when sorting connections
59#
60# Revision 1.20  2003/01/02 15:40:48  mardan
61# Merged patch from Marceln, which removes unused variables, more understandable
62# memory allocation error message, check to exit when there are no NAT connections
63# and making netstat-nat compatible with uLibC.
64# Updated files to v1.4.2
65#
66# Revision 1.19  2002/09/22 20:10:19  mardan
67# Added '-v: print version'
68# Added 'uninstall' to Makefile
69# Updated all other files.
70#
71# Revision 1.18  2002/09/22 17:16:08  mardan
72# Rewritten connection_table to allocate memory dynamicly.
73#
74# Revision 1.17  2002/09/12 19:32:12  mardan
75# Added display local connections to NAT box self
76# Updated README
77# Small changes in Makefile
78#
79# Revision 1.16  2002/09/08 20:23:48  mardan
80# Added sort by connection option. (source/destination IP/port)
81# Updated README and man-page.
82#
83# Revision 1.15  2002/08/07 19:25:59  mardan
84# Fixed bug, displayed wrong icmp connection in state REPLIED (dest was gateway).
85#
86# Revision 1.14  2002/08/07 19:02:54  mardan
87# Fixed 'icmp' bug. Segmentation fault occured when displaying NATed icmp connections.
88#
89# Revision 1.13  2002/08/06 19:32:54  mardan
90# Added small feature: no header output.
91# Lots of code cleanup.
92#
93# Revision 1.12  2002/08/03 00:22:22  mardan
94# Added portname resolving based on the listed names in 'services'.
95# Re-arranged the layout.
96# Added a Makefile and a header file.
97# Updated the README.
98#
99# Revision 1.11  2002/07/12 20:05:54  mardan
100# Added argument for extended view of hostnames.
101# Moved display-code into one function.
102# Removed most unnessacery code.
103# Updated README
104#
105# Revision 1.10  2002/07/10 19:58:33  mardan
106# Added filtering by destination-host, re-arranged some code to work properly.
107# Tested DNAT icmp and udp.(pls report if any bugs occur)
108# Fixed a few declaration bugs.
109#
110# Revision 1.9  2002/07/09 20:00:36  mardan
111# Added fully DNAT support (udp & icmp not fully tested yet, but should work),
112# including argument support for (S)(D)NAT selection.
113# Re-arranged layout code, can possible merged into one function.
114# Some few minor changes.
115# Started to work on destination-host selection.
116#
117# Revision 1.8  2002/07/07 20:27:47  mardan
118# Added display by source host/IP.
119# Made a few fixes/changes.
120# Updated the REAMDE.
121#
122# Revision 1.7  2002/06/30 19:55:41  mardan
123# Added README and COPYING (license) FILES.
124#
125# Revision 1.6  2002/06/23 16:27:26  mardan
126# Finished udp.
127# Maybe some layout changes in future? therwise tool is finished.
128#
129# Revision 1.5  2002/06/23 14:07:46  mardan
130# Added protocol arg option.
131# Todo: udp protocol
132#
133# Revision 1.4  2002/06/23 12:57:35  mardan
134# Added ident strings for test :-)
135#
136# Revision 1.3  2002/06/23 12:47:08  mardan
137# Fixed resolved hostname hussle-up/layout
138# Moved all source code into netstat-nat.c
139#
140# Revision 1.2  2002/06/23 11:56:09  mardan
141# Added NAT icmp display.
142# Still need to do udp (more states possible)
143# Really need to fix resolved hostnames display, still hussled up.
144#
145# Revision 1.1.1.1  2002/05/04 01:08:06  mardan
146# Initial import of netstat-nat, the C version.
147# Array pointers really needs to be fixed, still lots of other bugs..
148# So far only TCP displayed.
149# No commandline args for e.g. no_nameresolving, protocol.
150#
151#
152#
153# Copyright (c) 2006 by D.Wijsman (danny@tweegy.nl).
154# All rights reserved.
155#
156# This program is free software; you can redistribute it and/or modify it
157# under the terms of the GNU General Public License as published by the Free
158# Software Foundation; either version 2 of the License, or (at your option)
159# any later version.
160#
161# This program is distributed in the hope that it will be useful, but WITHOUT
162# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
163# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
164# more details.
165#
166# You should have received a copy of the GNU General Public License
167# along with this program; see the file COPYING.  If not, write to
168# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
169#
170#
171#-------------------------------------------------------------------------------
172*/
173
174
175typedef struct _ip_addresses
176{
177    char ip[16];
178    char dev[16];
179    struct _ip_addresses *prev;
180    struct _ip_addresses *next;
181} sIpAddresses;
182#include "netstat-nat.h"
183
184static char const rcsid[] = "$Id: netstat-nat.c,v 1.33 2010/01/09 19:34:24 danny Exp $";
185char SRC_IP[50];
186char DST_IP[50];
187int SNAT = 1;
188int DNAT = 1;
189int LOCAL = 0;
190int ROUTED = 0;
191static char PROTOCOL[4];
192int connection_index = 0;
193char ***connection_table;
194struct _ip_addresses *IpAddresses = NULL;
195
196
197int main(int argc, char *argv[])
198    {
199    const char *args = "hnp:s:d:SDxor:L?vNR";
200    static int SORT_ROW = 1;
201    static int EXT_VIEW = 0;
202    static int RESOLVE = 1;
203    static int no_hdr = 0;
204    static int NAT_HOP = 0;
205    FILE *f;
206    char line[350];
207    char src[50];
208    char dst[50];
209    char host[50];
210    char buf[100];
211    char buf2[100];
212    char from[50] = "NATed Address";
213    char nathost[50] = "NAT-host Address";
214    char dest[50] = "Destination Address";
215    char *ret;
216
217    char ***pa;
218    char *store;
219    int index, a, b, c, j, r;
220
221    /* variables to display routed and/or local connections */
222    struct ifconf ifc;
223    struct ifreq *req;
224    struct sockaddr_in *ipaddr;
225    char *ifbuf, *facename,  *ptr;
226    int facefound, lastlen, len, sock;
227    //IpAddresses = NULL;
228
229    // check parameters
230    while ((c = getopt(argc, argv, args)) != -1) {
231	switch (c) {
232	case 'h':
233	    display_help();
234	    return 1;
235	case '?':
236	    display_help();
237	    return 1;
238	case 'v':
239	    printf("Version %s\n", VERSION);
240	    return(0);
241	case 'n':
242	    RESOLVE = 0;
243	    break;
244	case 'p':
245	    strcopy(PROTOCOL, sizeof(PROTOCOL), optarg);
246	    break;
247	case 's':
248	    strcopy(SRC_IP, sizeof(SRC_IP), optarg);
249	    lookup_ip(SRC_IP, sizeof(SRC_IP));
250	    break;
251	case 'd':
252	    strcopy(DST_IP, sizeof(DST_IP), optarg);
253	    lookup_ip(DST_IP, sizeof(DST_IP));
254	    break;
255	case 'S':
256	    DNAT = 0;
257	    break;
258	case 'D':
259	    SNAT = 0;
260	    break;
261	case 'L':
262	    SNAT = 0;
263	    DNAT = 0;
264	    LOCAL = 1;
265	    ROUTED = 0;
266	    break;
267	case 'R':
268	    SNAT = 0;
269	    DNAT = 0;
270	    LOCAL = 0;
271	    ROUTED = 1;
272	    break;
273	case 'x':
274	    EXT_VIEW = 1;
275	    break;
276	case 'o':
277	    no_hdr = 1;
278	    break;
279	case 'N':
280	    NAT_HOP = 1;
281	    break;
282	case 'r':
283	    if (optarg == NULL || optarg == '\0') {
284		display_help();
285		return 1;
286		}
287	    if (strcmp(optarg, "scr") == 0) SORT_ROW = 1; //default
288	    if (strcmp(optarg, "dst") == 0) SORT_ROW = 2;
289	    if (strcmp(optarg, "src-port") == 0) SORT_ROW = 3;
290	    if (strcmp(optarg, "dst-port") == 0) SORT_ROW = 4;
291	    if (strcmp(optarg, "state") == 0) SORT_ROW = 5;
292	    break;
293	}
294    }
295    // some param checks
296    if (LOCAL == 1 || ROUTED == 1) {
297	SNAT = 0;
298	DNAT = 0;
299	NAT_HOP = 0;
300    }
301    // get local IP addresses
302    if (ROUTED || LOCAL) {
303	// find all interfaces
304
305	sock = socket(PF_INET, SOCK_DGRAM, 0);
306	lastlen = 0;
307	len = 100 * sizeof(struct ifreq);
308	for(;;) {
309	    if((ifbuf = malloc(len)) == NULL) {
310    		perror("malloc");
311    		exit(EXIT_FAILURE);
312	    }
313	    ifc.ifc_buf = ifbuf;
314	    ifc.ifc_len = len;
315
316	    if(ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
317    		if(errno != EINVAL || lastlen != 0) {
318    		    perror("ioctl:SIOCGIFCONF");
319    		    exit(EXIT_FAILURE);
320    		}
321	    } else {
322		if(ifc.ifc_len == lastlen)
323		// success //
324    		    break;
325    		lastlen = ifc.ifc_len;
326	    }
327	    // increment buffer //
328	    len += 10 * sizeof(struct ifreq);
329	    free(ifbuf);
330	}
331	// store all local addresses in memory //
332        for(ptr = ifbuf; ptr < ifbuf + ifc.ifc_len; ) {
333	    req = (struct ifreq *)ptr;
334	    ipaddr = (struct sockaddr_in *) &req->ifr_addr;
335//	    printf("The IP address associated with %s is %s\n", req->ifr_name, inet_ntoa(ipaddr->sin_addr));
336	    ip_addresses_add(&IpAddresses, req->ifr_name, inet_ntoa(ipaddr->sin_addr));
337	    ptr += sizeof(struct ifreq);
338	}
339	if (ifbuf) {
340	    free(ifbuf);
341	}
342    }
343
344    connection_table = (char ***) xcalloc((1) * sizeof(char **));
345    // some checking for IPTables and read file
346    if ((f = fopen(NF_CONNTRACK_LOCATION, "r")) == NULL) {
347	if ((f = fopen(IP_CONNTRACK_LOCATION, "r")) == NULL) {
348	    printf("Could not read info about connections from the kernel, make sure netfilter is enabled in kernel or by modules.\n");
349	    return 1;
350	}
351    }
352
353    // process conntrack table
354    if (!no_hdr) {
355	if (LOCAL || ROUTED) {
356	    strcopy(from, sizeof(from), "Source Address");
357	    strcopy(dest, sizeof(dest), "Destination Address");
358	    }
359	if (!EXT_VIEW) {
360	    printf("%-6s%-36s", "Proto", from);
361	    if (NAT_HOP && !LOCAL) {
362		printf("%-36s", nathost);
363	    }
364	    printf("%-36s%-6s" ,dest, "State");
365	    printf("\n");
366	} else {
367	    printf("%-6s%-41s", "Proto", from);
368	    if (NAT_HOP && !LOCAL) {
369		printf("%-41s", nathost);
370	    }
371	    printf("%-41s%-6s" ,dest, "State");
372	    printf("\n");
373	    }
374	}
375
376    // bugfix for proper read-in on some systems, provided by Supaflyster
377    while (!feof(f))
378    {
379	ret = fgets(line, sizeof(line), f);
380	if (strlen(line) > 0) {
381    	    process_entry(line);
382	}
383	memset(line, 0, sizeof(line));
384    }
385    fclose(f);
386
387    // create index of arrays pointed to main connection array
388    if (connection_index == 0) {
389	// There are no connections at this moment! free mem and exit
390	free(connection_table);
391        ip_addresses_free(&IpAddresses);
392	return (0);
393    }
394
395    pa = (char ***) xcalloc((connection_index) * sizeof(char **));
396
397    for (index = 0; index < connection_index; index++) {
398	pa[index] = (char **) xcalloc((ROWS) * sizeof(char *));
399
400	for (j = 0; j < ROWS; j++) {
401	    pa[index][j] = &connection_table[index][j][0];
402	    }
403	}
404    // sort by protocol and defined row
405    for (a = 0; a < connection_index - 1; a++) {
406	for (b = a + 1; b < connection_index; b++) {
407	    r = strcmp(pa[a][0], pa[b][0]);
408	    if (r > 0) {
409		for (j = 0; j < ROWS; j++) {
410		    store = pa[a][j];
411		    pa[a][j] = pa[b][j];
412		    pa[b][j] = store;
413		    }
414		}
415	    if (r == 0) {
416		if (strcmp(pa[a][SORT_ROW], pa[b][SORT_ROW]) > 0) {
417		    for (j = 0; j < ROWS; j++) {
418			store = pa[a][j];
419			pa[a][j] = pa[b][j];
420			pa[b][j] = store;
421			}
422		    }
423		}
424	    }
425	}
426
427    // print connections
428    for (index = 0; index < connection_index; index++) {
429	if (RESOLVE) {
430	    lookup_hostname(&pa[index][1]);
431	    lookup_hostname(&pa[index][2]);
432	    lookup_hostname(&pa[index][6]);
433	    if (strlen(pa[index][3]) > 0 || strlen(pa[index][4]) > 0 || strlen(pa[index][7]) > 0) {
434		lookup_portname(&pa[index][3], pa[index][0]);
435		lookup_portname(&pa[index][4], pa[index][0]);
436		lookup_portname(&pa[index][7], pa[index][0]);
437	    	}
438	    }
439	if (!EXT_VIEW) {
440	    strcopy(buf, sizeof(buf), "");
441	    strncat(buf, pa[index][1], 34 - strlen(pa[index][3]));
442	    if (!strcmp(pa[index][0], "tcp") || !strcmp(pa[index][0], "udp")) {
443                snprintf(buf2, sizeof(buf2), "%s:%s", buf, pa[index][3]);
444	    }
445            else {
446                snprintf(buf2, sizeof(buf2), "%s", buf);
447            }
448            snprintf(src, sizeof(src),  "%-36s", buf2);
449	    strcopy(buf, sizeof(buf), "");
450	    strncat(buf, pa[index][2], 34 - strlen(pa[index][4]));
451	    if (!strcmp(pa[index][0], "tcp") || !strcmp(pa[index][0], "udp")) {
452                snprintf(buf2, sizeof(buf2), "%s:%s", buf, pa[index][4]);
453	    }
454            else {
455	        snprintf(buf2, sizeof(buf2), "%s", buf);
456            }
457	    snprintf(dst, sizeof(dst), "%-36s", buf2);
458	    if (NAT_HOP) {
459		strcopy(buf, sizeof(buf), "");
460		strncat(buf, pa[index][6], 34 - strlen(pa[index][7]));
461		if (!strcmp(pa[index][0], "tcp") || !strcmp(pa[index][0], "udp")) {
462            	    snprintf(buf2, sizeof(buf2), "%s:%s", buf, pa[index][7]);
463		}
464        	else {
465	    	    snprintf(buf2, sizeof(buf2), "%s", buf);
466        	}
467		snprintf(host, sizeof(dst), "%-36s", buf2);
468	    }
469	} else {
470	    strcopy(buf, sizeof(buf), "");
471	    strncat(buf, pa[index][1], 39 - strlen(pa[index][3]));
472	    if (!strcmp(pa[index][0], "tcp") || !strcmp(pa[index][0], "udp")) {
473	        snprintf(buf2, sizeof(buf2), "%s:%s", buf, pa[index][3]);
474	    }
475            else {
476	        snprintf(buf2, sizeof(buf2), "%s", buf);
477	    }
478            snprintf(src , sizeof(src), "%-41s", buf2);
479	    strcopy(buf, sizeof(buf), "");
480	    strncat(buf, pa[index][2], 39 - strlen(pa[index][4]));
481	    if (!strcmp(pa[index][0], "tcp") || !strcmp(pa[index][0], "udp")) {
482	        snprintf(buf2, sizeof(buf2), "%s:%s", buf, pa[index][4]);
483	    }
484            else {
485	        snprintf(buf2, sizeof(buf2), "%s", buf);
486	    }
487            snprintf(dst, sizeof(dst), "%-41s", buf2);
488	    if (NAT_HOP) {
489		strcopy(buf, sizeof(buf), "");
490		strncat(buf, pa[index][6], 39 - strlen(pa[index][7]));
491		if (!strcmp(pa[index][0], "tcp") || !strcmp(pa[index][0], "udp")) {
492            	    snprintf(buf2, sizeof(buf2), "%s:%s", buf, pa[index][7]);
493		}
494        	else {
495	    	    snprintf(buf2, sizeof(buf2), "%s", buf);
496        	}
497		snprintf(host, sizeof(dst), "%-41s", buf2);
498	    }
499	}
500	printf("%-6s%s", pa[index][0], src);
501	if (NAT_HOP) {
502	    printf("%s", host);
503	}
504	printf("%s%-11s", dst, pa[index][5]);
505	printf("\n");
506
507    }
508
509    ip_addresses_free(&IpAddresses);
510
511    for (a = 0; a < connection_index; a++) {
512	for (j = 0; j < ROWS; j++) {
513	    if (connection_table[a][j] != NULL) free(connection_table[a][j]);
514	}
515	free(connection_table[a]);
516	free(pa[a]);
517    }
518    free(connection_table);
519    free(pa);
520    return(0);
521}
522
523// get protocol
524int get_protocol(char *line, char *protocol)
525{
526    int i,j, protocol_nr;
527    char protocol_name[11] = "";
528    char protocol_raw[6] = "";
529
530    if (string_search(line, "tcp")) {
531        memcpy(protocol, "tcp", 3);
532    }
533    else if (string_search(line, "udp")) {
534        memcpy(protocol, "udp", 3);
535    }
536    else if (string_search(line, "icmp")) {
537        memcpy(protocol, "icmp", 4);
538    }
539    else {
540        // here we search for protocol number and give it a name (get_protocol_name)
541        for (i = 0; i < strlen(line); i++ ) {
542            if(!strncmp(&line[i], "unknown  ", 9)) {
543                i += 9;
544                for (j = i; j < strlen(line); j++) {
545                    if (line[j] == ' ') {
546                        break;
547                    }
548                    strncat(protocol_raw, &line[j], 1);
549                }
550                protocol_nr = atoi(protocol_raw);
551                get_protocol_name(protocol_name, protocol_nr);
552                memcpy(protocol, protocol_name, 5);
553                break;
554            }
555        }
556        //memcpy(protocol, "raw", 3);
557    }
558//    printf("PROTO: %s\n", protocol);
559    return(0);
560}
561
562// get connection status
563int get_connection_state(char *line, char *state)
564{
565    if (string_search(line, "ESTABLISHED")) {
566        memcpy(state, "ESTABLISHED", 11);
567    }
568    else if (string_search(line, "TIME_WAIT")) {
569        memcpy(state, "TIME_WAIT", 9);
570    }
571    else if (string_search(line, "FIN_WAIT")) {
572        memcpy(state, "FIN_WAIT", 8);
573    }
574    else if (string_search(line, "SYN_RECV")) {
575        memcpy(state, "SYN_RECV", 8);
576    }
577    else if (string_search(line, "SYN_SENT")) {
578        memcpy(state, "SYN_SENT", 8);
579    }
580    else if (string_search(line, "UNREPLIED")) {
581        memcpy(state, "UNREPLIED", 9);
582    }
583    else if (string_search(line, "CLOSE")) {
584        memcpy(state, "CLOSE", 5);
585    }
586    else if (string_search(line, "ASSURED")) {
587        memcpy(state, "ASSURED", 7);
588    }
589    else {
590        if (string_search(line, "udp")) {
591            memcpy(state, "UNREPLIED", 9);
592        }
593        else {
594            memcpy(state, " ", 1);
595        }
596    }
597//    printf("STATE: %s\n", state);
598    return(0);
599}
600
601void process_entry(char *line)
602{
603    int count = 0;
604    char srcip_f[16] = "";
605    char dstip_f[16] = "";
606    char srcip_s[16] = "";
607    char dstip_s[16] = "";
608    char srcport[6] = "";
609    char dstport[6] = "";
610    char srcport_s[6] = "";
611    char dstport_s[6] = "";
612    char protocol[5] = "";
613    char state[12] = "";
614
615    search_first_hit("src=", line, srcip_f);
616    search_first_hit("dst=", line, dstip_f);
617    search_sec_hit("src=", line, srcip_s);
618    search_sec_hit("dst=", line, dstip_s);
619    search_first_hit("sport=", line, srcport);
620    search_first_hit("dport=", line, dstport);
621    search_sec_hit("sport=", line, srcport_s);
622    search_sec_hit("dport=", line, dstport_s);
623
624    get_protocol(line, protocol);
625    if (strcmp(PROTOCOL, "")) {
626        if (strncmp(PROTOCOL, protocol, 3)) {
627//            printf("RETURN\n");
628            return;
629        }
630    }
631    get_connection_state(line, state);
632    if (SNAT) {
633	if ((!strcmp(srcip_f, dstip_s) == 0) && (strcmp(dstip_f, srcip_s) == 0)) {
634  	    check_src_dst(protocol, srcip_f, dstip_f, srcport, dstport, dstip_s, dstport_s, state);
635	    }
636    }
637    if (DNAT) {
638	if ((strcmp(srcip_f, dstip_s) == 0) && (!strcmp(dstip_f, srcip_s) == 0)) {
639	    check_src_dst(protocol, srcip_f, srcip_s, srcport, srcport_s, dstip_f, dstport_s, state);
640	}
641    }
642    // bugfix for displaying dnat over snat connections, submitted by Supaflyster (intercepted traffic to DNAT) (2 interfaces)
643    if (DNAT || SNAT) {
644	if ((!strcmp(srcip_f, srcip_s) == 0) && (!strcmp(srcip_f, dstip_s) == 0) && (!strcmp(dstip_f, srcip_s) == 0) && (!strcmp(dstip_f, dstip_s) == 0) ) {
645	    check_src_dst(protocol, srcip_f, srcip_s, srcport, srcport_s, dstip_s, dstport_s, state);
646	}
647    }
648    // (DNAT) (1 interface)
649    if (DNAT) {
650	if ((!strcmp(srcip_f, srcip_s) == 0) && (!strcmp(srcip_f, dstip_s) == 0) && (!strcmp(dstip_f, srcip_s) == 0) && (strcmp(dstip_f, dstip_s) == 0) ) {
651	    check_src_dst(protocol, srcip_f, srcip_s, srcport, srcport_s, dstip_s, dstport_s, state);
652	}
653    }
654    if (LOCAL) {
655        if ((strcmp(srcip_f, dstip_s) == 0) && (strcmp(dstip_f, srcip_s) == 0)
656	    && ((ip_addresses_search(IpAddresses, srcip_f) == 1) || (ip_addresses_search(IpAddresses, srcip_s) == 1)
657	    || (ip_addresses_search(IpAddresses, dstip_f) == 1) || (ip_addresses_search(IpAddresses, dstip_s) == 1))) {
658            check_src_dst(protocol, srcip_f, srcip_s, srcport, dstport, "", "", state);
659	}
660    }
661    if (ROUTED) {
662        if ((strcmp(srcip_f, dstip_s) == 0) && (strcmp(dstip_f, srcip_s) == 0)
663	    && (ip_addresses_search(IpAddresses, srcip_f) == 0) && (ip_addresses_search(IpAddresses, srcip_s) == 0)
664	    && (ip_addresses_search(IpAddresses, dstip_f) == 0) && (ip_addresses_search(IpAddresses, dstip_s) == 0)) {
665            check_src_dst(protocol, srcip_f, srcip_s, srcport, dstport, "", "", state);
666	}
667    }
668//    printf("%s %s %s %s %s %s\n", protocol, srcip_f, dstip_f, srcip_s, dstip_s, state);
669}
670
671
672// -- Internal used functions
673// Check filtering by source and destination IP
674void check_src_dst(char *protocol, char *src_ip, char *dst_ip, char *src_port, char *dst_port, char *nathostip, char *nathostport, char *status)
675    {
676    if ((check_if_source(src_ip)) && (strcmp(DST_IP, "") == 0)) {
677	store_data(protocol, src_ip, dst_ip, src_port, dst_port, nathostip, nathostport, status);
678	}
679    else if ((check_if_destination(dst_ip)) && (strcmp(SRC_IP, "") == 0)) {
680	store_data(protocol, src_ip, dst_ip, src_port, dst_port, nathostip, nathostport, status);
681	}
682    else if ((check_if_destination(dst_ip)) && (check_if_source(src_ip))) {
683	store_data(protocol, src_ip, dst_ip, src_port, dst_port, nathostip, nathostport, status);
684	}
685    }
686
687void store_data(char *protocol, char *src_ip, char *dst_ip, char *src_port, char *dst_port, char *nathostip, char *nathostport, char *status)
688    {
689
690    connection_table = (char ***) xrealloc(connection_table, (connection_index +1) * sizeof(char **));
691    connection_table[connection_index] = (char **) xcalloc(200 * sizeof(char *));
692    connection_table[connection_index][0] = (char *) xcalloc(10);
693    connection_table[connection_index][1] = (char *) xcalloc(60);
694    connection_table[connection_index][2] = (char *) xcalloc(60);
695    connection_table[connection_index][3] = (char *) xcalloc(20);
696    connection_table[connection_index][4] = (char *) xcalloc(20);
697    connection_table[connection_index][5] = (char *) xcalloc(15);
698    connection_table[connection_index][6] = (char *) xcalloc(60);
699    connection_table[connection_index][7] = (char *) xcalloc(20);
700
701    strcopy(connection_table[connection_index][3], 20, src_port);
702    strcopy(connection_table[connection_index][4], 20, dst_port);
703    strcopy(connection_table[connection_index][1], 60, src_ip);
704    strcopy(connection_table[connection_index][2], 60, dst_ip);
705    strcopy(connection_table[connection_index][0], 10, protocol);
706    strcopy(connection_table[connection_index][5], 15, status);
707    strcopy(connection_table[connection_index][6], 60, nathostip);
708    strcopy(connection_table[connection_index][7], 20, nathostport);
709    connection_index++;
710    }
711
712void lookup_portname(char **port, char *proto)
713    {
714    char buf_port[10];
715    int portnr;
716    struct servent *service;
717    size_t port_size;
718
719    strcopy(buf_port, sizeof(buf_port), *port);
720    portnr = htons(atoi(buf_port));
721
722    if ((service = getservbyport(portnr, proto))) {
723	//port_size = strlen(service->s_name) + 8;
724        //*port = xrealloc(*port, port_size); hmm double alloction
725	strcopy(*port, 20, service->s_name);
726	}
727    }
728
729void extract_ip(char *gen_buffer)
730    {
731    char *split;
732    split = strtok(gen_buffer, "=");
733    split = strtok(NULL, "=");
734    strcpy(gen_buffer, split);
735    }
736
737int lookup_hostname(char **r_host)
738    {
739    int addr;
740    struct hostent *hp;
741    char **p;
742    size_t r_host_size;
743
744    addr = inet_addr(*r_host);
745    if ((hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET)) == NULL)
746	return 0;
747
748    for (p = hp->h_addr_list; *p != 0; p++){
749	struct in_addr in;
750	(void)memcpy(&in.s_addr, *p, sizeof(in.s_addr));
751	//r_host_size = strlen(*r_host) + 25;
752	//*r_host = xrealloc(*r_host, r_host_size); hmm double allocation
753	strcopy(*r_host, 60, hp->h_name);
754	}
755    return 0;
756    }
757
758
759int lookup_ip(char *hostname, size_t hostname_size)
760    {
761    char *ip;
762    struct hostent *hp;
763    struct in_addr ip_addr;
764
765    if ((hp = gethostbyname(hostname)) == NULL) {
766	printf("Unknown host: %s\n", hostname);
767	exit(-1);
768	}
769
770    ip_addr = *(struct in_addr *)(hp->h_addr);
771    ip = inet_ntoa(*(struct in_addr *)(hp->h_addr));
772    strcopy(hostname, hostname_size, ip);
773    return 1;
774    }
775/*
776int match(char *string, char *pattern)
777    {
778    int i;
779    regex_t re;
780    char buf[200];
781
782    i = regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB);
783
784    if (i != 0) {
785	(void)regerror(i, &re, buf, sizeof(buf));
786	return 0;
787	}
788
789    i = regexec(&re, string, (size_t) 0, NULL, 0);
790    regfree(&re);
791
792    if (i != 0) {
793	(void)regerror(i, &re, buf, sizeof(buf));
794	return 0;
795	}
796
797    return 1;
798    }
799*/
800int check_if_source(char *host)
801    {
802    if ((strcmp(host, SRC_IP) == 0) || (strcmp(SRC_IP, "") == 0)) {
803	return 1;
804	}
805    return 0;
806    }
807
808int check_if_destination(char *host)
809    {
810    if ((strcmp(host, DST_IP) == 0) || (strcmp(DST_IP, "") == 0)) {
811	return 1;
812	}
813    return 0;
814    }
815
816
817static void *xcalloc(size_t bufsize)
818    {
819    void *buf;
820
821    if ((buf = calloc(1, bufsize)) != NULL) {
822	return buf;
823    } else {
824	printf("Could not allocate memory (%i bytes); %s.\n -- Exiting.\n", bufsize, strerror(errno));
825	exit(1);
826	}
827    }
828
829
830static void *xrealloc(void *oldbuf, size_t newbufsize)
831    {
832    void *newbuf;
833
834    if ((newbuf = realloc(oldbuf, newbufsize)) != NULL) {
835	return newbuf;
836    } else {
837	printf("Could not allocate memory (%i bytes); %s.\n -- Exiting.\n", newbufsize, strerror(errno));
838	exit(1);
839	}
840    }
841
842char *xstrdup (const char *dup)
843{
844    char *ret;
845    if ((ret = strdup(dup)) == NULL) {
846	printf("Could not set value into struct (%s); %s.\n -- Exiting.\n", dup, strerror(errno));
847	exit(EXIT_FAILURE);
848    }
849    return ret;
850}
851
852void ip_addresses_add(struct _ip_addresses **list, const char *dev, const char *ip)
853{
854    struct _ip_addresses *new = malloc(sizeof * new);
855    if (new != NULL) {
856	strncpy(new->ip, ip, 15);
857	strncpy(new->dev, dev, 15);
858	new->next = NULL;
859	if (*list == NULL) {
860	    *list = new;
861	}
862	else {
863	    struct _ip_addresses *tail = *list;
864	    while (tail->next != NULL)
865	    {
866		tail = tail->next;
867	    }
868	    tail->next = new;
869	}
870    }
871}
872
873int ip_addresses_search(struct _ip_addresses *list, const char *ip)
874{
875    struct _ip_addresses *akt = list;
876    if (list == NULL) return 0;
877    while (akt != NULL)
878    {
879	if (strcmp (akt->ip, ip) == 0) {
880	    return 1;
881	}
882	akt = akt->next;
883    }
884    return 0;
885}
886
887void ip_addresses_free(struct _ip_addresses **node)
888{
889    struct _ip_addresses *this = *node;
890    struct _ip_addresses *temp;
891    while (this != NULL)
892    {
893	temp = this->next;
894	free(this);
895	this = temp;
896    }
897    *node = NULL;
898}
899
900int string_search(char *string, char *search)
901{
902    int searchLen;
903    int i;
904    searchLen = strlen(search);
905    if (searchLen > strlen(string)) {
906	return(0); // this can't match
907    }
908    for (i = 0; i < strlen(string) - searchLen + 1; i++) {
909	if (!strncasecmp((char *)&string[i], search, searchLen)) {
910	    return(1); // we got hit
911	}
912    }
913    return(0);
914}
915
916
917int search_first_hit(char *search, char *line, char *ret)
918{
919    unsigned int searchLen;
920    unsigned int i;
921    unsigned int j;
922    unsigned int lineLen;
923
924    lineLen = strlen(line);
925    searchLen = strlen(search);
926
927    if (searchLen > lineLen) {
928	return(1); // this can't match, invalid data?
929    }
930    for (i = 0; i < lineLen - searchLen + 1; i++) {
931	if (!strncasecmp((char *)&line[i], search, searchLen)) {
932	    break; // we got hit
933	}
934    }
935    for (j = i + searchLen; j < i + 15 + searchLen; j++) {
936        if (j > lineLen) {
937            return(1); // incomplete data
938        }
939        if (line[j] == ' ') {
940            break; // we reach _space_ delimiter
941        }
942    }
943    memcpy(ret, &line[i + searchLen], j - i - searchLen);
944    return(0);
945}
946
947
948int search_sec_hit(char *search, char *line, char *ret)
949{
950    unsigned int searchLen;
951    unsigned int i;
952    unsigned int j;
953    unsigned int got_first = 0;
954    unsigned int lineLen;
955
956    lineLen = strlen(line);
957    searchLen = strlen(search);
958
959    if (searchLen > lineLen) {
960	return(1); // this can't match, invalid data?
961    }
962    for (i = 0; i < lineLen - searchLen + 1; i++) {
963	if (!strncasecmp((char *)&line[i], search, searchLen)) {
964	    if (got_first) {
965                break; // we got hit (second)
966            }
967            got_first = 1;
968	}
969    }
970    for (j = i + searchLen; j < i + 15 + searchLen; j++) {
971        if (j > lineLen) {
972            return(1); // incomplete data
973        }
974        if (line[j] == ' ') {
975            break; // we reach _space_ delimiter
976        }
977    }
978    memcpy(ret, &line[i + searchLen], j - i - searchLen);
979    return(0);
980}
981
982
983void get_protocol_name(char *protocol_name, int protocol_nr)
984{
985    struct protoent *proto_struct;
986    char strconvers[10] = "";
987    proto_struct = getprotobynumber(protocol_nr);
988    if (proto_struct != NULL) {
989        memcpy(protocol_name, proto_struct->p_name, 5);
990    }
991    else {
992        snprintf(strconvers, 6, "%d", protocol_nr);
993        memcpy(protocol_name, strconvers, 5);
994    }
995}
996
997
998void display_help()
999{
1000    printf("args: -h: displays this help\n");
1001    printf("      -n: don't resolve host/portnames\n");
1002    printf("      -p <protocol>        : display connections by protocol\n");
1003    printf("      -s <source-host>     : display connections by source\n");
1004    printf("      -d <destination-host>: display connections by destination\n");
1005    printf("      -S: display SNAT connections\n");
1006    printf("      -D: display DNAT connections (default: SNAT & DNAT)\n");
1007    printf("      -L: display only connections to NAT box itself (doesn't show SNAT & DNAT)\n");
1008    printf("      -R: display only connections routed through the NAT box (doesn't show SNAT & DNAT)\n");
1009    printf("      -x: extended hostnames view\n");
1010    printf("      -r src | dst | src-port | dst-port | state : sort connections\n");
1011    printf("      -o: strip output header\n");
1012    printf("      -N: display NAT box connection information (only valid with SNAT & DNAT)\n");
1013    printf("      -v: print version\n");
1014    printf("\n");
1015    printf("      netstat-nat [-S|-D|-L|-R] [-no]\n");
1016    printf("      netstat-nat [-nxo]\n");
1017}
1018
1019// -- End of internal used functions
1020
1021// -- The End --
1022