[syslog-ng] TTL patch, helpful for multicasting logs

Alexander Clouter ac56 at soas.ac.uk
Thu Mar 30 16:13:05 CEST 2006


Hi,

After my earlier multicast patch I quickly realised that if syslog-ng is 
actually sending UDP multicast syslog data the TTL on the IP packets is by 
default 1.  This results in the packet being expired at the gateway and never 
being able to leave the subnet....not too handy :(

After clobbering it around for a few days I have rolled out this patch to 
address the problem which should be applied in addition, and after, the 
multicast patch I released the other day (also re-included in this email).

The patch adds a new parameter to the destination tcp()/udp() drivers called 
ttl() and it takes a number between 0 and 255.  When set to zero, it uses the 
default kernel parameter[1] but when set to 1->255 the TTL on the packet 
being sent is set to this.  Of course if the parameter is not specified it 
defaults to zero.

This should now allow you to use

destination du_moo { udp("239.1.2.3" port(514) ttl(7)); };

in your config files.  It works on unicast traffic too, I guess you could use
it as a layer of defence to guarentee that your syslog packets never leave
your network by setting the TTL to a low value.  I always wanted to get
around to emailing the samba folk a TTL patch to do this sort of thing, so
roaming samba laptop users could get some feeling of security that only the
local network can get access to their shares....however this is now getting a
bit offtopic :)

Hope you all find it useful, now back to my multicasting syslog cluster :)

Cheers

Alex

[1] under linux its one, and probably the same for most OS's
-------------- next part --------------
Only in syslog-ng-1.9.9/src: .deps
diff -u syslog-ng-1.9.9.orig/src/gsockaddr.c syslog-ng-1.9.9/src/gsockaddr.c
--- syslog-ng-1.9.9.orig/src/gsockaddr.c	2006-02-11 18:37:02.000000000 +0000
+++ syslog-ng-1.9.9/src/gsockaddr.c	2006-03-28 11:41:14.058514000 +0100
@@ -91,6 +91,12 @@
         }
       rc = G_IO_STATUS_NORMAL;
     }
+
+  if (g_in_multicast(fd, addr))
+    {
+      return G_IO_STATUS_ERROR;
+    }
+  
   return rc;
 }
 
@@ -610,6 +616,41 @@
 
 #endif
 
+int
+g_in_multicast(int fd, GSockAddr *addr)
+{
+  struct ip_mreq mreq;
+#if ENABLED_IPV6
+  struct ipv6_mreq mreq6;
+#endif
+  
+  switch (addr->sa.sa_family)
+    {
+#if ENABLE_IPV6
+      case AF_INET6:
+	if (IN6_IS_ADDR_MULTICAST(&(((GSockAddrInet6 *) addr)->sin6.sin6_addr)))
+	  {
+            memcpy(&mreq6.ipv6mr_multiaddr, &((GSockAddrInet6 *) addr)->sin6->sin6_addr.s_addr), sizeof(struct in6_addr));
+            mreq6.ipv6mr_interface.s_addr=0;
+            if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0)
+		return 1;
+	  }
+	break;
+#endif
+      case AF_INET:
+	if (IN_MULTICAST(ntohl(((GSockAddrInet *) addr)->sin.sin_addr.s_addr)))
+	  {
+            mreq.imr_multiaddr.s_addr=((GSockAddrInet *) addr)->sin.sin_addr.s_addr;
+            mreq.imr_interface.s_addr=INADDR_ANY;
+            if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+		return 1;
+	  }
+	break;
+    }
+  
+  return 0;
+}
+
 /* AF_UNIX socket address */
 
 /*+
diff -u syslog-ng-1.9.9.orig/src/gsockaddr.h syslog-ng-1.9.9/src/gsockaddr.h
--- syslog-ng-1.9.9.orig/src/gsockaddr.h	2006-02-11 18:36:32.000000000 +0000
+++ syslog-ng-1.9.9/src/gsockaddr.h	2006-03-28 11:34:32.508514000 +0100
@@ -73,6 +73,8 @@
 
 #endif
 
+int g_in_multicast(int fd, GSockAddr *addr);
+
 GSockAddr *g_sockaddr_unix_new(gchar *name);
 GSockAddr *g_sockaddr_unix_new2(struct sockaddr_un *s_un, int sunlen);
 
Only in syslog-ng-1.9.9/src: Makefile
-------------- next part --------------
diff -u syslog-ng-1.9.9.orig/src/afinet.c syslog-ng-1.9.9/src/afinet.c
--- syslog-ng-1.9.9.orig/src/afinet.c	2006-02-12 12:03:15.000000000 +0000
+++ syslog-ng-1.9.9/src/afinet.c	2006-03-30 13:53:46.868514000 +0100
@@ -56,6 +56,24 @@
 }
 
 static void
+afinet_set_ttl(GSockAddr *addr, gint ttl)
+{
+  if (addr)
+    {
+      if (ttl>=0 && ttl<=255)
+        {
+	  addr->ttl = (char) ttl;
+	}
+        else
+        {
+          msg_error("Error ttl must be higher than zero and less than 255",
+                        NULL);
+          return;
+        }
+    }  
+}
+
+static void
 afinet_set_ip(GSockAddr *addr, gchar *ip)
 {
   if (addr && !inet_aton(ip, &((struct sockaddr_in *) &addr->sa)->sin_addr))
@@ -120,6 +138,14 @@
 }
 
 void 
+afinet_dd_set_ttl(LogDriver *s, gint ttl)
+{
+  AFInetDestDriver *self = (AFInetDestDriver *) s;
+  
+  afinet_set_ttl(self->super.dest_addr, ttl);
+}
+
+void 
 afinet_dd_set_localip(LogDriver *s, gchar *ip)
 {
   AFInetDestDriver *self = (AFInetDestDriver *) s;
diff -u syslog-ng-1.9.9.orig/src/afinet.h syslog-ng-1.9.9/src/afinet.h
--- syslog-ng-1.9.9.orig/src/afinet.h	2006-02-11 07:37:58.000000000 +0000
+++ syslog-ng-1.9.9/src/afinet.h	2006-03-30 14:30:20.328514000 +0100
@@ -47,6 +47,7 @@
 LogDriver *afinet_dd_new(gchar *host, gint port, guint flags);
 void afinet_dd_set_localport(LogDriver *self, gint port, gchar *service, gchar *proto);
 void afinet_dd_set_destport(LogDriver *self, gint port, gchar *service, gchar *proto);
+void afinet_dd_set_ttl(LogDriver *self, gint ttl);
 void afinet_dd_set_localip(LogDriver *self, gchar *ip);
 void afinet_dd_set_sync_freq(LogDriver *self, gint sync_freq);
 
diff -u syslog-ng-1.9.9.orig/src/cfg-grammar.y syslog-ng-1.9.9/src/cfg-grammar.y
--- syslog-ng-1.9.9.orig/src/cfg-grammar.y	2006-02-26 08:31:44.000000000 +0000
+++ syslog-ng-1.9.9/src/cfg-grammar.y	2006-03-30 14:30:43.368514000 +0100
@@ -88,7 +88,7 @@
 
 /* socket related options */
 %token KW_KEEP_ALIVE KW_MAX_CONNECTIONS
-%token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT 
+%token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT KW_TTL
 
 /* misc options */
 %token KW_USE_TIME_RECVD
@@ -559,6 +559,7 @@
 dest_afinet_option
 	: KW_LOCALIP '(' string ')'		{ afinet_dd_set_localip(last_driver, $3); free($3); }
 	| KW_PORT '(' NUMBER ')'		{ afinet_dd_set_destport(last_driver, $3, NULL, NULL); }
+	| KW_TTL '(' NUMBER ')'			{ afinet_dd_set_ttl(last_driver, $3); }
 	| dest_writer_option
 	;
 
diff -u syslog-ng-1.9.9.orig/src/cfg-lex.l syslog-ng-1.9.9/src/cfg-lex.l
--- syslog-ng-1.9.9.orig/src/cfg-lex.l	2006-02-26 08:31:35.000000000 +0000
+++ syslog-ng-1.9.9/src/cfg-lex.l	2006-03-30 13:39:40.568514000 +0100
@@ -113,6 +113,7 @@
 	{ "ip",			KW_IP },
 	{ "localport",		KW_LOCALPORT },
 	{ "port",		KW_PORT },
+	{ "ttl",		KW_TTL },
 	{ "destport",		KW_DESTPORT },
 	{ "owner",		KW_OWNER },
 	{ "group",		KW_GROUP },
diff -u syslog-ng-1.9.9.orig/src/gsockaddr.c syslog-ng-1.9.9/src/gsockaddr.c
--- syslog-ng-1.9.9.orig/src/gsockaddr.c	2006-03-30 14:32:54.008514000 +0100
+++ syslog-ng-1.9.9/src/gsockaddr.c	2006-03-30 13:52:14.488514000 +0100
@@ -158,6 +158,10 @@
     }
   else
     {
+      if (g_ttl(fd, remote))
+        {
+	  return G_IO_STATUS_ERROR;
+	}
       return G_IO_STATUS_NORMAL;
     }
 }
@@ -287,6 +291,7 @@
   GSockAddrFuncs *sa_funcs;
   int salen;
   struct sockaddr_in sin;
+  char ttl;
 } GSockAddrInet;
 
 /*+ private function to prepare an IPv4 style bind, e.g. set
@@ -361,6 +366,7 @@
       addr->sin.sin_family = AF_INET;
       addr->sin.sin_port = htons(port);
       addr->sin.sin_addr = ina;
+      addr->ttl = 0;
       addr->sa_funcs = &inet_sockaddr_funcs;
     }
   return (GSockAddr *) addr;
@@ -396,6 +402,9 @@
             }
         }
     }
+
+  addr->ttl = 0;
+  
   return (GSockAddr *) addr;
   
 }
@@ -421,6 +430,7 @@
   addr->flags = 0;
   addr->salen = sizeof(struct sockaddr_in);
   addr->sin = *sin;
+  addr->ttl = 0;
   addr->sa_funcs = &inet_sockaddr_funcs;
   
   return (GSockAddr *) addr;
@@ -439,6 +449,7 @@
   GSockAddrFuncs *sa_funcs;
   int salen;
   struct sockaddr_in sin;
+  char ttl;
   gpointer options;
   guint options_length;
   guint16 min_port, max_port, last_port;
@@ -459,6 +470,9 @@
       g_error("SockAddrInetRange, invalid range given; min_port='%d', max_port='%d'", addr->min_port, addr->max_port);
       return G_IO_STATUS_ERROR;
     }
+
+  addr->ttl = 0;
+  
   for (port = addr->last_port; port <= addr->max_port; port++)
     {
       /* attempt to bind */
@@ -502,6 +516,7 @@
   addr->sin.sin_family = AF_INET;
   inet_aton(ip, &addr->sin.sin_addr);
   addr->sin.sin_port = 0;
+  addr->ttl = 0;
   addr->sa_funcs = &inet_range_sockaddr_funcs;
   if (max_port > min_port)
     {
@@ -529,6 +544,7 @@
   GSockAddrFuncs *sa_funcs;
   int salen;
   struct sockaddr_in6 sin6;
+  char ttl;
 } GSockAddrInet6;
 
 /*+ format an IPv6 address into human readable form */
@@ -582,6 +598,7 @@
   addr->sin6.sin6_family = AF_INET6;
   inet_pton(AF_INET6, ip, &addr->sin6.sin6_addr);
   addr->sin6.sin6_port = htons(port);
+  addr->ttl = 0;
   addr->sa_funcs = &inet6_sockaddr_funcs;
   
   return (GSockAddr *) addr;
@@ -609,6 +626,7 @@
   addr->flags = 0;
   addr->salen = sizeof(struct sockaddr_in6);
   addr->sin6 = *sin6;
+  addr->ttl = 0;
   addr->sa_funcs = &inet6_sockaddr_funcs;
   
   return (GSockAddr *) addr;
@@ -651,6 +669,47 @@
   return 0;
 }
 
+int
+g_ttl(int fd, GSockAddr *addr)
+{
+  if (addr->ttl == 0)
+  {
+    return 0;
+  }
+	
+  switch (addr->sa.sa_family)
+    {
+#if ENABLE_IPV6
+      case AF_INET6:
+	if (IN6_IS_ADDR_MULTICAST(&(((GSockAddrInet6 *) addr)->sin6.sin6_addr)))
+	  {
+            if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &addr->ttl, sizeof(addr->ttl)) < 0)
+		return 1;
+	  }
+	else
+	  {
+	    if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &addr->ttl, sizeof(addr->ttl)) < 0)
+		return 1;
+	  }
+	break;
+#endif
+      case AF_INET:
+	if (IN_MULTICAST(ntohl(((GSockAddrInet *) addr)->sin.sin_addr.s_addr)))
+	  {
+            if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &addr->ttl, sizeof(addr->ttl)) < 0)
+		return 1;
+	  }
+	else
+	  {
+	    if (setsockopt(fd, IPPROTO_IP, IP_TTL, &addr->ttl, sizeof(addr->ttl)) < 0)
+		return 1;
+	  }
+	break;
+    }
+  
+  return 0;
+}
+
 /* AF_UNIX socket address */
 
 /*+
diff -u syslog-ng-1.9.9.orig/src/gsockaddr.h syslog-ng-1.9.9/src/gsockaddr.h
--- syslog-ng-1.9.9.orig/src/gsockaddr.h	2006-03-30 14:32:54.008514000 +0100
+++ syslog-ng-1.9.9/src/gsockaddr.h	2006-03-30 14:31:24.218514000 +0100
@@ -44,6 +44,7 @@
   GSockAddrFuncs *sa_funcs;
   int salen;
   struct sockaddr sa;
+  char ttl;
 } GSockAddr;
 
 struct _GSockAddrFuncs 
@@ -74,6 +75,7 @@
 #endif
 
 int g_in_multicast(int fd, GSockAddr *addr);
+int g_ttl(int fd, GSockAddr *addr);
 
 GSockAddr *g_sockaddr_unix_new(gchar *name);
 GSockAddr *g_sockaddr_unix_new2(struct sockaddr_un *s_un, int sunlen);



More information about the syslog-ng mailing list