Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Apr 2008 06:01:26 -0500
From:      "David Todd" <mobilepolice@gmail.com>
To:        freebsd-net@freebsd.org
Cc:        seki@fexx.org
Subject:   custom modifications to libalias for detailed translation information (patch included)
Message-ID:  <b91012310804280401g3a71e577k908546972a96e2c4@mail.gmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Gentlemen,

I've expanded upon the work of Masahiro Sekiguchi <seki@fexx.org>'s
patch for libalias located at:
http://www.fexx.org/ybb/alias_db.c.diff.txt

This alias_db.c diff modified libalias in a way to replace the
original /var/log/alias.log file with one that reported running
statistics in a format like such:

+ udp 219.63.255.49:1024 211.5.1.219:53 219.63.255.49:1024 *:* (0x8060100)
+ udp 219.63.255.49:1024 165.76.0.98:53 219.63.255.49:1024 *:* (0x8060180)
+ udp 219.63.255.49:1024 165.76.4.2:53 219.63.255.49:1024 *:* (0x8060200)
+ udp 219.63.255.49:1024 211.5.1.217:53 219.63.255.49:1024 *:* (0x8060280)
+ tcp 192.168.1.188:1346 210.142.46.154:80 219.63.255.49:1346 *:* (0x8060300)
+ udp 219.63.255.49:1024 210.141.108.194:53 219.63.255.49:1024 *:* (0x8060400)
+ udp 219.63.255.49:1024 210.239.166.194:53 219.63.255.49:1024 *:* (0x8060480)

Obviously this patch was built for a much older version of libalias;
circa 2003. I recently attempted to convert his work, modify it
(relatively heavily) for my own uses
and what I think makes a bit better sense; after a few weeks of
testing and repeated modifications I'm ready to give it to whomever
thinks they could make use of it.

The highlights of my changes:
* alias.log becomes 'alias' under /var/log; it is no longer a massive
running list of connection #'s per protocol, but a one-line file
updated every 20 seconds showing current protocol #'s.
* alias.details is a new log under /var/log which provides interesting
information on all of the active translated connections in a format
that looks like this:

total: 485
time: 1209374774
last_chg   exp_t T-     protocol        source addr:port         dest
addr:port        alias addr:port        proxy addr:port
1209374770 00060 -00056 udp             192.0.21.10:8080
78.109.177.139:61878                *:8080                 *:*
1209374733 00010  00000 tcp DIS:DIS     192.0.21.10:3276
209.85.133.18:80       68.52.101.103:3276                 *:*
1209374635 00060  00000 icmp          68.52.101.103:1
67.15.240.42:256      68.52.101.103:1                    *:*
1209374566 00300 -00092 tcp EST:DWN   68.52.101.103:11225
69.60.111.193:39357    68.52.101.103:11225                *:*
1209374747 00010  00000 tcp DIS:DIS     192.0.21.10:3261
209.85.133.19:80       68.52.101.103:3261                 *:*
1209374078 00300  00000 tcp PERMLNK     192.0.21.10:5580
  *:*                    *:5580                 *:*

(if your email client supports tabbed text properly the format of the
log looks much cleaner)

* modified TCP_EXPIRE_CONNECTED from 24 hours to 1 hour (did this for
debugging purposes, it can be set to whatever standard there is) I ran
into this bug:
BUG: when a TCP connection is dropped locally (behind the nat) or
remotely, sometimes libalias/natd does not mark the translated TCP
connection as down/disconnected/dead. The connection will remain
in the translation tables until libalias/natd is reloaded. This could
be just a problem with natd but I do not have the proper tools or
environment to figure out exactly where the problem is coming from,
leading to this:
* modification: when idelta > lnk->expire_time and LINK_TCP in
IncrementalCleanup(), SetStateIn/Out ALIAS_TCP_NOT_CONNECTED, reset
lnk->timestamp to current la->timeStamp and set lnk->expire_time to
TCP_EXPIRE_SINGLEDEAD; on the pass after next of the
IncrementalCleanup() function we'll come across the same translation
entry, if it hasn't changed we'll expire it.

The issue here is that after a period of time I had 1500+ TCP
connections in my translation tables all showing a "time to expire" of
0 seconds (out of 86400); and no activity on the network to warrant
such connections.

In normal TCP connections when a packet is processed for a translation
entry lnk->timestamp is updated, so idelta will never exceed
lnk->expire_time as long as the link is actually communicating
packets; I feel like this was a safe compromise and it has not
negatively affected my computing habits yet - but granted, I am
neither a power user nor everyone else, so this
solution/hack/crapshoot is open for interpritation. It's my experience
with most commercial firewalls will drop inactive links after 15
min-1hr, etc.


I've abused calls to AliasLog with this patch. I'm still a relative
novice to C programming and memory management, so the last thing I
wanted to deal with was mallocing crap and working with string
buffers/etc and create all kinds of havoc. I'm not sure what sort of
impact this has on the performance of the program; from my experience
I've had 6000+ established UDP and TCP connections going at once (with
about 800KB/s load) and my 1Ghz Celeron machine has seen about 30%
load; it's important to note that libalias was rewriting the
alias.details log every 75 state changes, instead of every 20 seconds
like it does now; so it's likely the load will be significantly lower.

I know there's been some recent changes to alias_db.c in the CVS which
I did not have at the time I started making these changes, so I tried
to keep what I've changed to a minimum in order to insure an easy
patching process if any of you decide to implement this.

Thanks to Masahiro Sekiguchi for his original work as an inspiration
for me to do this; I don't know if anyone else uses ipfw/natd anymore
(I know I do!) but if they do, they might find this useful.

Any comments are appreciated.

Regards,
David Todd

[-- Attachment #2 --]
--- alias_db.c.orig	2008-04-08 18:31:15.000000000 -0500
+++ alias_db.c	2008-04-28 04:14:03.000000000 -0500
@@ -159,6 +159,7 @@
 
 #include <sys/socket.h>
 #include <netinet/tcp.h>
+#include <arpa/inet.h>
 
 #ifdef _KERNEL  
 #include <netinet/libalias/alias.h>
@@ -210,7 +211,7 @@
 
 /* When the link is up */
 #ifndef TCP_EXPIRE_CONNECTED
-#define TCP_EXPIRE_CONNECTED   86400
+#define TCP_EXPIRE_CONNECTED   3600		// old: 86400 (24 hours) ?!
 #endif
 
 
@@ -306,7 +307,7 @@
 #define LINK_ADDR                     (IPPROTO_MAX + 3)
 #define LINK_PPTP                     (IPPROTO_MAX + 4)
 
-	int		flags;	/* indicates special characteristics   */
+	int		flags;	/* indicates special recharacteristics   */
 	int		pflags;	/* protocol-specific flags */
 
 /* flag bits */
@@ -404,6 +405,10 @@
 #endif
 
 /* Log file control */
+static void	ShowLinkType(struct alias_link *, struct libalias *);
+static void	ShowAddrAndPort(struct in_addr, u_short, struct libalias *);
+static void	ShowAliasDetails(struct libalias *);
+
 static void	ShowAliasStats(struct libalias *);
 static int	InitPacketAliasLog(struct libalias *);
 static void	UninitPacketAliasLog(struct libalias *);
@@ -460,7 +465,7 @@
 AliasLog(char *str, const char *format, ...)
 {		
 	va_list ap;
-	
+
 	va_start(ap, format);
 	vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
 	va_end(ap);
@@ -470,7 +475,7 @@
 AliasLog(FILE *stream, const char *format, ...)
 {
 	va_list ap;
-	
+
 	va_start(ap, format);
 	vfprintf(stream, format, ap);
 	va_end(ap);
@@ -478,13 +483,148 @@
 }
 #endif
 
+
+/*
+ * Function: ShowLinkType()
+ * Return  : nothing
+ * Side Eff: call AliasLog with results of the link type, if link_type = LINK_TCP
+ *  call GetStateIn/Out(lnk) to provide more details about the current TCP state.
+ * Calls   : AliasLog, GetStateIn, GetStateOut
+*/
+static void
+ShowLinkType(struct alias_link *lnk, struct libalias *la)
+{
+#ifndef _KERNEL
+
+	switch (lnk->link_type) {
+		case LINK_ICMP:         AliasLog(la->logDetails, "%-11s ", "icmp");       break;
+		case LINK_TCP:
+			AliasLog(la->logDetails, "tcp ");
+			if (lnk->flags & LINK_PERMANENT) {
+				AliasLog(la->logDetails, "PERMLNK ");
+			} else {
+				switch (GetStateIn(lnk)) {
+					case ALIAS_TCP_STATE_CONNECTED:		AliasLog(la->logDetails, "EST:"); break;
+					case ALIAS_TCP_STATE_DISCONNECTED:	AliasLog(la->logDetails, "DIS:"); break;
+					case ALIAS_TCP_STATE_NOT_CONNECTED:	AliasLog(la->logDetails, "DWN:"); break;
+					default:				AliasLog(la->logDetails, "UNK:"); break;
+				}
+				switch (GetStateOut(lnk)) {
+                                        case ALIAS_TCP_STATE_CONNECTED:         AliasLog(la->logDetails, "EST "); break;
+                                        case ALIAS_TCP_STATE_DISCONNECTED:      AliasLog(la->logDetails, "DIS "); break;
+                                        case ALIAS_TCP_STATE_NOT_CONNECTED:     AliasLog(la->logDetails, "DWN "); break;
+                                        default:                                AliasLog(la->logDetails, "UNK "); break;
+                                }
+			}
+			break;
+		case LINK_UDP:          AliasLog(la->logDetails, "%-11s ", "udp");        break;
+		case LINK_FRAGMENT_ID:  AliasLog(la->logDetails, "%-11s ", "[frag_id]");  break;
+		case LINK_FRAGMENT_PTR: AliasLog(la->logDetails, "%-11s ", "[frag_ptr]"); break;
+		case LINK_ADDR:         AliasLog(la->logDetails, "%-11s ", "[addr]");     break;
+		case LINK_PPTP:         AliasLog(la->logDetails, "%-11s ", "[pptp]");     break;
+		default:                AliasLog(la->logDetails, "[%-9d] ", lnk->link_type);       break;
+	}
+#endif
+}
+
+/*
+ * Function: ShowAddrAndPort()
+ * Return  : nothing
+ * Side Eff: simple expression for output of IP address and port or "*:*"
+ *  to logDetails log file. Implemented to prevent code repeition.
+ * Calls   : AliasLog
+*/
+static void
+ShowAddrAndPort(struct in_addr addr, u_short port, struct libalias *la)
+{
+#ifndef _KERNEL
+	if (la->logDetails) {
+		AliasLog(la->logDetails,
+			port == 0 ? "%15s:*      " : "%15s:%-6u ",
+			addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(addr),
+			ntohs(port));
+	}
+#endif
+}
+
+
+/*
+ * Function: ShowAliasDetails(struct libalias *)
+ * Return  : nothing
+ * Side Eff: Walk our list of links every 20 seconds, abusively call AliasLog
+ *  to output details of all of our links to /var/log/alias.details; this function
+ *  will not write to the output file in kld-mode.
+ * Calls   : AliasLog (abusively), ShowAddrAndPort, ShowLinkType, 
+*/
+static void
+ShowAliasDetails(struct libalias *la)
+{
+
+	if ((la->lastDetailsTime + 20) <= la->timeStamp) {		// update every 20 seconds.
+		la->lastDetailsTime = la->timeStamp;
+	} else {
+		return;
+	}
+
+	ShowAliasStats(la);
+
+#ifndef _KERNEL
+	if (la->logDetails) {
+
+		struct alias_link *lk;
+		int i;
+
+		freopen(NULL, "w", la->logDetails);		// zero our stream and reopen.
+
+		LIBALIAS_LOCK_ASSERT(la);
+
+		AliasLog(la->logDetails,			// write header to stream
+		"total: %d\n" \
+		"time: %d\n" \
+		"last_chg   exp_t T-     protocol        source addr:port         dest addr:port        alias addr:port        proxy addr:port\n",
+		la->icmpLinkCount + la->udpLinkCount + la->tcpLinkCount + la->pptpLinkCount +
+		la->protoLinkCount + la->fragmentIdLinkCount + la->fragmentPtrLinkCount,
+		la->timeStamp);
+
+		for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {		// probably should time this function to measure impact.
+			lk = LIST_FIRST(&la->linkTableOut[i]);
+			while (lk != NULL) {
+				struct alias_link *lk_next;
+				lk_next = LIST_NEXT(lk, list_out);
+
+				AliasLog(la->logDetails, "%10d %5.5d %6.5d ",
+					lk->timestamp,			// time of last packet through connection
+					lk->expire_time,		// timeout period after last packet
+					(la->timeStamp - lk->expire_time) > lk->timestamp ? 0 : la->timeStamp - (lk->timestamp + lk->expire_time));
+					// don't need to see positive values, easier to look through the log for "00000"
+
+				ShowLinkType(lk, la);
+				ShowAddrAndPort(lk->src_addr, lk->src_port, la);	// source (internal address)
+				ShowAddrAndPort(lk->dst_addr, lk->dst_port, la);	// dest (external address)
+				ShowAddrAndPort(lk->alias_addr, lk->alias_port, la);	// alias (our public address)
+				ShowAddrAndPort(lk->proxy_addr, lk->proxy_port, la);	// proxy ?
+				AliasLog(la->logDetails, "\n");
+
+				lk = lk_next;
+			}
+		}
+	}
+#endif
+}
+
+
 static void
 ShowAliasStats(struct libalias *la)
 {
 
 	LIBALIAS_LOCK_ASSERT(la);
-/* Used for debugging */
+
 	if (la->logDesc) {
+
+#ifndef _KERNEL
+		freopen(NULL, "w", la->logDesc);		// zero our stream and start from the top
+#endif
+
 		int tot  = la->icmpLinkCount + la->udpLinkCount + 
 			la->tcpLinkCount + la->pptpLinkCount +
 			la->protoLinkCount + la->fragmentIdLinkCount +
@@ -814,17 +954,15 @@
 CleanupAliasData(struct libalias *la)
 {
 	struct alias_link *lnk;
-	int i, icount;
+	int i;
 
 	LIBALIAS_LOCK_ASSERT(la);
-	icount = 0;
 	for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
 		lnk = LIST_FIRST(&la->linkTableOut[i]);
 		while (lnk != NULL) {
 			struct alias_link *link_next;
 
 			link_next = LIST_NEXT(lnk, list_out);
-			icount++;
 			DeleteLink(lnk);
 			lnk = link_next;
 		}
@@ -837,11 +975,9 @@
 static void
 IncrementalCleanup(struct libalias *la)
 {
-	int icount;
 	struct alias_link *lnk;
 
 	LIBALIAS_LOCK_ASSERT(la);
-	icount = 0;
 	lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
 	while (lnk != NULL) {
 		int idelta;
@@ -852,21 +988,23 @@
 		switch (lnk->link_type) {
 		case LINK_TCP:
 			if (idelta > lnk->expire_time) {
-				struct tcp_dat *tcp_aux;
-
-				tcp_aux = lnk->data.tcp;
-				if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
-				    || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) {
+				if (GetStateIn(lnk) != ALIAS_TCP_STATE_CONNECTED
+				    || GetStateOut(lnk) != ALIAS_TCP_STATE_CONNECTED) {
 					DeleteLink(lnk);
-					icount++;
+				} else {
+					/* expire_time is up, set the link as disconnected, on the pass
+					 * 120s from now if it's still disconnected then we'll dump the link.
+					 */
+					SetStateIn(lnk, ALIAS_TCP_STATE_NOT_CONNECTED);
+					SetStateOut(lnk, ALIAS_TCP_STATE_NOT_CONNECTED);
+					lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
+					lnk->timestamp = la->timeStamp;
 				}
 			}
 			break;
 		default:
-			if (idelta > lnk->expire_time) {
+			if (idelta > lnk->expire_time)
 				DeleteLink(lnk);
-				icount++;
-			}
 			break;
 		}
 		lnk = link_next;
@@ -943,13 +1081,15 @@
 		break;
 	}
 
-/* Free memory */
-	free(lnk);
 
 /* Write statistics, if logging enabled */
 	if (la->packetAliasMode & PKT_ALIAS_LOG) {
-		ShowAliasStats(la);
+		ShowAliasDetails(la);
 	}
+
+/* Free memory */
+        free(lnk);
+
 }
 
 
@@ -1089,7 +1229,7 @@
 #endif
 	}
 	if (la->packetAliasMode & PKT_ALIAS_LOG) {
-		ShowAliasStats(la);
+		ShowAliasDetails(la);
 	}
 	return (lnk);
 }
@@ -2262,8 +2402,15 @@
 		if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
 			;
 #else 		
-		if ((la->logDesc = fopen("/var/log/alias.log", "w")))
+		if ((la->logDesc = fopen("/var/log/alias", "w")))
 			fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");	       
+		else
+			return (ENOMEM);
+
+		if ((la->logDetails = fopen("/var/log/alias.details", "w"))) {
+			fprintf(la->logDetails, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
+			la->lastDetailsTime = la->timeStamp;
+		}
 #endif
 		else 
 			return (ENOMEM); /* log initialization failed */
@@ -2284,6 +2431,10 @@
 		free(la->logDesc);
 #else
 		fclose(la->logDesc);
+		if (la->logDetails) {
+			fclose(la->logDetails);
+			la->logDetails = NULL;
+		}
 #endif
 		la->logDesc = NULL;
 	}
--- alias_local.h.orig	2008-04-09 17:46:25.000000000 -0500
+++ alias_local.h	2008-04-28 02:53:26.000000000 -0500
@@ -100,6 +100,8 @@
 	int		fragmentPtrLinkCount;
 	int		sockCount;
 
+	int		lastDetailsTime;
+
 	int		cleanupIndex;	/* Index to chain of link table    */
 	/* being inspected for old links   */
 
@@ -120,6 +122,7 @@
 	char           *logDesc;        
 #else 
 	FILE           *logDesc;	
+	FILE           *logDetails;
 #endif
 	/* statistics monitoring */
 

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?b91012310804280401g3a71e577k908546972a96e2c4>