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

Balazs Scheidler bazsi at balabit.hu
Mon May 1 00:43:58 CEST 2006


On Thu, 2006-03-30 at 15:13 +0100, Alexander Clouter wrote:
> 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 :(

I have now implemented generic socket option setup code and support for
TTL and multicast. The patch below does that. It has no real connection
to the code that you posted, as I tried to minimize the effect on
GSockAddr, as it encapsulates a socket address but nothing else.

I also added support for some long awaited socket options like SO_RCVBUF
and SO_SNDBUF, but broadcast support was also added.

Sending seems to work well, I have not tested receive and IPv6 support.
Documentation is not yet updated, these are the new keywords to be
applied to various socket drivers (unix-dgram, unix-stream, udp, tcp,
udp6 and tcp6):

--- orig/src/cfg-lex.l
+++ mod/src/cfg-lex.l
@@ -117,6 +117,12 @@ static struct keyword keywords[] = {
        { "localport",          KW_LOCALPORT },
        { "port",               KW_PORT },
        { "destport",           KW_DESTPORT },
+        { "ip_ttl",             KW_IP_TTL },
+        { "ip_tos",             KW_IP_TOS },
+        { "so_broadcast",       KW_SO_BROADCAST },
+        { "so_rcvbuf",          KW_SO_RCVBUF },
+        { "so_sndbuf",          KW_SO_SNDBUF },
+
        { "owner",              KW_OWNER },
        { "group",              KW_GROUP },
        { "perm",               KW_PERM },


Multicast is enabled if the bind/target address is a multicast address.


-- 
Bazsi
-------------- next part --------------
* looking for devel at balabit.hu--other-1/syslog-ng--mainline--2.0--patch-45 to compare with
* comparing to devel at balabit.hu--other-1/syslog-ng--mainline--2.0--patch-45
M  src/afinet.c
M  src/afinet.h
M  src/afsocket.c
M  src/afsocket.h
M  src/afunix.h
M  src/cfg-grammar.y
M  src/cfg-lex.l
M  src/gsockaddr.h

* modified files

--- orig/src/afinet.c
+++ mod/src/afinet.c
@@ -28,6 +28,7 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
+
 static void
 afinet_set_port(GSockAddr *addr, gint port, gchar *service, gchar *proto)
 {
@@ -92,7 +93,7 @@ afinet_resolve_name(GSockAddr *addr, gch
               break;
 #if ENABLE_IPV6
             case AF_INET6:
-              g_sockaddr_inet6_set_address(addr, ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
+              g_sockaddr_inet6_set_address(addr, &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
               break;
 #endif
             default: 
@@ -130,6 +131,70 @@ afinet_resolve_name(GSockAddr *addr, gch
     }
 }
 
+static gboolean
+afinet_setup_socket(gint fd, gboolean listener, GSockAddr *addr, InetSocketOptions *sock_options)
+{
+  gint off = 0;
+  
+  if (!afsocket_setup_socket(fd, listener, &sock_options->super))
+    return FALSE;
+
+  switch (addr->sa.sa_family)
+    {
+    case AF_INET:
+      {
+        struct ip_mreq mreq;
+
+        if (IN_MULTICAST(g_sockaddr_inet_get_address(addr).s_addr))
+          {
+            if (sock_options->ttl)
+              setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &sock_options->ttl, sizeof(sock_options->ttl));
+              
+            memset(&mreq, 0, sizeof(mreq));
+            mreq.imr_multiaddr = g_sockaddr_inet_get_address(addr);
+            mreq.imr_interface.s_addr = INADDR_ANY;
+            setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
+            setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &off, sizeof(off));
+            
+          }
+        else
+          {
+            if (sock_options->ttl)
+              setsockopt(fd, SOL_IP, IP_TTL, &sock_options->ttl, sizeof(sock_options->ttl));
+          }        
+        if (sock_options->tos)
+          setsockopt(fd, SOL_IP, IP_TOS, &sock_options->tos, sizeof(sock_options->tos));
+          
+        break;
+      }
+#if ENABLE_IPV6
+    case AF_INET6:
+      {
+        struct ipv6_mreq mreq6;
+        
+        if (IN6_IS_ADDR_MULTICAST(g_sockaddr_inet6_get_address(addr)->s6_addr))
+          {
+            if (sock_options->ttl)
+              setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &sock_options->ttl, sizeof(sock_options->ttl));
+
+             memset(&mreq6, 0, sizeof(mreq6));
+             mreq6.ipv6mr_multiaddr = *g_sockaddr_inet6_get_address(addr);
+             mreq6.ipv6mr_interface = 0;
+             setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6));
+             setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off));
+          }
+        else
+          {
+            if (sock_options->ttl)
+              setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &sock_options->ttl, sizeof(sock_options->ttl));
+          }
+        break;
+      }
+#endif
+    }
+  return TRUE;
+}
+
 void 
 afinet_sd_set_localport(LogDriver *s, gint port, gchar *service, gchar *proto)
 {
@@ -146,6 +211,14 @@ afinet_sd_set_localip(LogDriver *s, gcha
   afinet_resolve_name(self->bind_addr, ip);
 }
 
+static gboolean
+afinet_sd_setup_socket(AFSocketSourceDriver *s, gboolean listener, gint fd)
+{
+  AFInetSourceDriver *self = (AFInetSourceDriver *) s;
+  
+  return afinet_setup_socket(fd, listener, self->super.bind_addr, &self->sock_options);
+}
+
 LogDriver *
 afinet_sd_new(gint af, gchar *host, gint port, guint flags)
 {
@@ -166,6 +239,7 @@ afinet_sd_new(gint af, gchar *host, gint
         host = "::";
     }
   afinet_resolve_name(self->super.bind_addr, host);
+  self->super.setup_socket = afinet_sd_setup_socket;
     
   return &self->super.super;
 }
@@ -196,6 +270,14 @@ afinet_dd_set_localip(LogDriver *s, gcha
   afinet_resolve_name(self->super.bind_addr, ip);
 }
 
+static gboolean
+afinet_dd_setup_socket(AFSocketDestDriver *s, gint fd)
+{
+  AFInetDestDriver *self = (AFInetDestDriver *) s;
+  
+  return afinet_setup_socket(fd, FALSE, self->super.dest_addr, &self->sock_options);
+}
+
 LogDriver *
 afinet_dd_new(gint af, gchar *host, gint port, guint flags)
 {
@@ -213,5 +295,6 @@ afinet_dd_new(gint af, gchar *host, gint
       self->super.dest_addr = g_sockaddr_inet6_new("::", port);
     }
   afinet_resolve_name(self->super.dest_addr, host);
+  self->super.setup_socket = afinet_dd_setup_socket;
   return &self->super.super;
 }


--- orig/src/afinet.h
+++ mod/src/afinet.h
@@ -26,9 +26,17 @@
 
 #include "afsocket.h"
 
+typedef struct _InetSocketOptions
+{
+  SocketOptions super;
+  gint ttl;
+  gint tos;
+} InetSocketOptions;
+
 typedef struct _AFInetSourceDriver
 {
   AFSocketSourceDriver super;
+  InetSocketOptions sock_options;
 } AFInetSourceDriver;
 
 LogDriver *afinet_sd_new(gint af, gchar *host, gint port, guint flags);
@@ -42,6 +50,7 @@ void afinet_sd_set_localip(LogDriver *se
 typedef struct _AFInetDestDriver
 {
   AFSocketDestDriver super;
+  InetSocketOptions sock_options;
 } AFInetDestDriver;
 
 LogDriver *afinet_dd_new(gint af, gchar *host, gint port, guint flags);


--- orig/src/afsocket.c
+++ mod/src/afsocket.c
@@ -154,6 +154,19 @@ typedef struct _AFSocketSourceConnection
 
 static void afsocket_sd_close_connection(AFSocketSourceDriver *self, AFSocketSourceConnection *sc);
 
+gboolean
+afsocket_setup_socket(gint fd, gboolean listener, SocketOptions *sock_options)
+{
+  if (sock_options->sndbuf)
+    setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sock_options->sndbuf, sizeof(sock_options->sndbuf));
+  if (sock_options->rcvbuf)
+    setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sock_options->rcvbuf, sizeof(sock_options->rcvbuf));
+  if (sock_options->broadcast)
+    setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &sock_options->broadcast, sizeof(sock_options->broadcast));
+    
+  return TRUE;
+}
+
 static gboolean
 afsocket_open_socket(GSockAddr *bind_addr, int stream_or_dgram, int *fd)
 {
@@ -359,6 +372,12 @@ afsocket_sd_accept(gpointer s)
                 NULL);
       return TRUE;
     }
+  if (self->setup_socket && !self->setup_socket(self, FALSE, new_fd))
+    {
+      close(new_fd);
+      return TRUE;
+    }
+    
   g_fd_set_nonblock(new_fd, TRUE);
   g_fd_set_cloexec(new_fd, TRUE);
     
@@ -440,6 +459,12 @@ afsocket_sd_init(LogPipe *s, GlobalConfi
           close(sock);
           return FALSE;
         }
+        
+      if (self->setup_socket && !self->setup_socket(self, TRUE, sock))
+        {
+          close(sock);
+          return FALSE;
+        }
 
       self->fd = sock;
       source = g_listen_source_new(self->fd);
@@ -459,6 +484,12 @@ afsocket_sd_init(LogPipe *s, GlobalConfi
             return self->super.optional;
         }
       self->fd = -1;
+
+      if (!self->setup_socket(self, FALSE, sock))
+        {
+          close(sock);
+          return FALSE;
+        }
       
       /* we either have self->connections != NULL, or sock contains a new fd */
       if (self->connections || afsocket_sd_process_connection(self, NULL, sock))
@@ -678,6 +709,12 @@ afsocket_dd_reconnect(AFSocketDestDriver
     {
       return FALSE;
     }
+    
+  if (self->setup_socket && !self->setup_socket(self, sock))
+    {
+      close(sock);
+      return FALSE;
+    }
   
   rc = g_connect(sock, self->dest_addr);
   if (rc == G_IO_STATUS_NORMAL)


--- orig/src/afsocket.h
+++ mod/src/afsocket.h
@@ -35,6 +35,16 @@
 #define AFSOCKET_KEEP_ALIVE          0x0100
 
 typedef struct _AFSocketSourceDriver AFSocketSourceDriver;
+typedef struct _AFSocketDestDriver AFSocketDestDriver;
+
+typedef struct _SocketOptions
+{
+  gint sndbuf;
+  gint rcvbuf;
+  gint broadcast;
+} SocketOptions;
+
+gboolean afsocket_setup_socket(gint fd, gboolean listener, SocketOptions *sock_options);
 
 struct _AFSocketSourceDriver
 {
@@ -49,7 +59,7 @@ struct _AFSocketSourceDriver
   gint num_connections;
   gint listen_backlog;
   GList *connections;
-  void (*open_connection)(struct _AFSocketSourceDriver *s, gint fd, struct sockaddr *sa, socklen_t salen);
+  gboolean (*setup_socket)(AFSocketSourceDriver *s, gboolean listener, gint fd);
 };
 
 void afsocket_sd_set_keep_alive(LogDriver *self, gint enable);
@@ -61,7 +71,7 @@ gboolean afsocket_sd_deinit(LogPipe *s, 
 void afsocket_sd_init_instance(AFSocketSourceDriver *self, guint32 flags);
 void afsocket_sd_free_instance(AFSocketSourceDriver *self);
 
-typedef struct _AFSocketDestDriver
+struct _AFSocketDestDriver
 {
   LogDriver super;
   guint32 flags;
@@ -74,7 +84,8 @@ typedef struct _AFSocketDestDriver
   GSockAddr *dest_addr;
   gint time_reopen;
   guint reconnect_timer;
-} AFSocketDestDriver;
+  gboolean (*setup_socket)(AFSocketDestDriver *s, gint fd);
+};
 
 void afsocket_dd_init_instance(AFSocketDestDriver *self, guint32 flags);
 


--- orig/src/afunix.h
+++ mod/src/afunix.h
@@ -34,6 +34,7 @@ typedef struct _AFUnixSourceDriver
   uid_t owner;
   gid_t group;
   mode_t perm;
+  SocketOptions sock_options;
 } AFUnixSourceDriver;
 
 void afunix_sd_set_uid(LogDriver *self, gchar *owner);
@@ -45,6 +46,7 @@ LogDriver *afunix_sd_new(gchar *filename
 typedef struct _AFUnixDestDriver
 {
   AFSocketDestDriver super;
+  SocketOptions sock_options;
 } AFUnixDestDriver;
 
 LogDriver *afunix_dd_new(gchar *filename, guint flags);


--- orig/src/cfg-grammar.y
+++ mod/src/cfg-grammar.y
@@ -35,6 +35,7 @@ LogDriver *last_driver;
 LogReaderOptions *last_reader_options;
 LogWriterOptions *last_writer_options;
 LogTemplate *last_template;
+SocketOptions *last_sock_options;
 gint last_addr_family = AF_INET;
 
 %}
@@ -92,6 +93,7 @@ gint last_addr_family = AF_INET;
 /* socket related options */
 %token KW_KEEP_ALIVE KW_MAX_CONNECTIONS
 %token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT 
+%token KW_IP_TTL KW_SO_BROADCAST KW_IP_TOS KW_SO_SNDBUF KW_SO_RCVBUF
 
 /* misc options */
 %token KW_USE_TIME_RECVD
@@ -235,6 +237,18 @@ template_item
 	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ log_template_set_escape(last_template, $3); }
 	;
 
+socket_option
+	: KW_SO_SNDBUF '(' NUMBER ')'           { last_sock_options->sndbuf = $3; }
+	| KW_SO_RCVBUF '(' NUMBER ')'           { last_sock_options->rcvbuf = $3; }
+	| KW_SO_BROADCAST '(' yesno ')'         { last_sock_options->broadcast = $3; }
+	;
+
+inet_socket_option
+	: socket_option
+	| KW_IP_TTL '(' NUMBER ')'              { ((InetSocketOptions *) last_sock_options)->ttl = $3; }
+	| KW_IP_TOS '(' NUMBER ')'              { ((InetSocketOptions *) last_sock_options)->tos = $3; }
+	;
+
 source_items
         : source_item ';' source_items		{ log_drv_append($1, $3); log_drv_unref($3); $$ = $1; }
 	|					{ $$ = NULL; }
@@ -298,6 +312,7 @@ source_afunix_dgram_params
 		AFSOCKET_DGRAM | AFSOCKET_LOCAL); 
 	    free($1); 
 	    last_reader_options = &((AFSocketSourceDriver *) last_driver)->reader_options;
+	    last_sock_options = &((AFUnixSourceDriver *) last_driver)->sock_options;
 	  }
 	  source_afunix_options			{ $$ = last_driver; }
 	;
@@ -310,6 +325,7 @@ source_afunix_stream_params
 		AFSOCKET_STREAM | AFSOCKET_KEEP_ALIVE | AFSOCKET_LOCAL);
 	    free($1);
 	    last_reader_options = &((AFSocketSourceDriver *) last_driver)->reader_options;
+	    last_sock_options = &((AFUnixSourceDriver *) last_driver)->sock_options;
 	  }
 	  source_afunix_options			{ $$ = last_driver; }
 	;
@@ -327,6 +343,7 @@ source_afunix_option
 	| KW_OPTIONAL '(' yesno ')'		{ last_driver->optional = $3; }
 	| source_afsocket_stream_params		{}
 	| source_reader_option			{}
+	| socket_option				{}
 	; 
 
 source_afinet_udp_params
@@ -336,6 +353,7 @@ source_afinet_udp_params
 			NULL, 514,
 			AFSOCKET_DGRAM);
 	    last_reader_options = &((AFSocketSourceDriver *) last_driver)->reader_options;
+	    last_sock_options = &((AFInetSourceDriver *) last_driver)->sock_options.super;
 	  }
 	  source_afinet_udp_options		{ $$ = last_driver; }
 	;
@@ -356,7 +374,8 @@ source_afinet_option
 	| KW_LOCALPORT '(' NUMBER ')'		{ afinet_sd_set_localport(last_driver, $3, NULL, NULL); }
 	| KW_PORT '(' NUMBER ')'		{ afinet_sd_set_localport(last_driver, $3, NULL, NULL); }
 	| KW_IP '(' string ')'			{ afinet_sd_set_localip(last_driver, $3); free($3); }
-	| source_reader_option			{}
+	| source_reader_option
+	| inet_socket_option
 	;
 
 source_afinet_tcp_params
@@ -366,6 +385,7 @@ source_afinet_tcp_params
 			NULL, 514,
 			AFSOCKET_STREAM);
 	    last_reader_options = &((AFSocketSourceDriver *) last_driver)->reader_options;
+	    last_sock_options = &((AFInetSourceDriver *) last_driver)->sock_options.super;
 	  }
 	  source_afinet_tcp_options	{ $$ = last_driver; }
 	;
@@ -526,8 +546,9 @@ dest_afunix_dgram_params
 	    last_driver = afunix_dd_new($1, AFSOCKET_DGRAM);
 	    free($1);
 	    last_writer_options = &((AFSocketDestDriver *) last_driver)->writer_options;
+	    last_sock_options = &((AFUnixDestDriver *) last_driver)->sock_options;
 	  }
-	  dest_writer_options			{ $$ = last_driver; }
+	  dest_afunix_options			{ $$ = last_driver; }
 	;
 
 dest_afunix_stream_params
@@ -536,10 +557,20 @@ dest_afunix_stream_params
 	    last_driver = afunix_dd_new($1, AFSOCKET_STREAM);
 	    free($1);
 	    last_writer_options = &((AFSocketDestDriver *) last_driver)->writer_options;
+	    last_sock_options = &((AFUnixDestDriver *) last_driver)->sock_options;
 	  }
-	  dest_writer_options			{ $$ = last_driver; }
+	  dest_afunix_options			{ $$ = last_driver; }
 	;
 
+dest_afunix_options
+	: dest_afunix_options dest_afunix_option
+	|
+	;
+
+dest_afunix_option
+	: dest_writer_option
+	| socket_option
+	;
 
 dest_afinet_udp_params
 	: string 	
@@ -549,6 +580,7 @@ dest_afinet_udp_params
 			AFSOCKET_DGRAM);
 	    free($1);
 	    last_writer_options = &((AFSocketDestDriver *) last_driver)->writer_options;
+	    last_sock_options = &((AFInetDestDriver *) last_driver)->sock_options.super;
 	  }
 	  dest_afinet_udp_options		{ $$ = last_driver; }
 	;
@@ -558,9 +590,11 @@ dest_afinet_udp_options
 	|
 	;
 
+
 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); }
+	| inet_socket_option
 	| dest_writer_option
 	;
 
@@ -579,6 +613,7 @@ dest_afinet_tcp_params
 			AFSOCKET_STREAM); 
 	    free($1);
 	    last_writer_options = &((AFSocketDestDriver *) last_driver)->writer_options;
+	    last_sock_options = &((AFInetDestDriver *) last_driver)->sock_options.super;
 	  }
 	  dest_afinet_tcp_options		{ $$ = last_driver; }
 	;


--- orig/src/cfg-lex.l
+++ mod/src/cfg-lex.l
@@ -117,6 +117,12 @@ static struct keyword keywords[] = {
 	{ "localport",		KW_LOCALPORT },
 	{ "port",		KW_PORT },
 	{ "destport",		KW_DESTPORT },
+        { "ip_ttl",             KW_IP_TTL },
+        { "ip_tos",             KW_IP_TOS },
+        { "so_broadcast",       KW_SO_BROADCAST },
+        { "so_rcvbuf",          KW_SO_RCVBUF },
+        { "so_sndbuf",          KW_SO_SNDBUF },
+
 	{ "owner",		KW_OWNER },
 	{ "group",		KW_GROUP },
 	{ "perm",		KW_PERM },


--- orig/src/gsockaddr.h
+++ mod/src/gsockaddr.h
@@ -64,7 +64,6 @@ void g_sockaddr_unref(GSockAddr *a);
 gboolean g_sockaddr_inet_check(GSockAddr *a);
 GSockAddr *g_sockaddr_inet_new(gchar *ip, guint16 port);
 GSockAddr *g_sockaddr_inet_new2(struct sockaddr_in *sin);
-GSockAddr *g_sockaddr_inet_new_resolve(const gchar *name, guint16 port);
 GSockAddr *g_sockaddr_inet_range_new(gchar *ip, guint16 min_port, guint16 max_port);
 
 static inline struct sockaddr *
@@ -160,10 +159,10 @@ g_sockaddr_inet6_get_sa(GSockAddr *s)
  * This GSockAddrInet specific function returns the address part of the
  * address.
  **/
-static inline struct in6_addr
+static inline struct in6_addr *
 g_sockaddr_inet6_get_address(GSockAddr *s)
 {
-  return g_sockaddr_inet6_get_sa(s)->sin6_addr;
+  return &g_sockaddr_inet6_get_sa(s)->sin6_addr;
 }
 
 /**
@@ -175,9 +174,9 @@ g_sockaddr_inet6_get_address(GSockAddr *
  * address.
  **/
 static inline void
-g_sockaddr_inet6_set_address(GSockAddr *s, struct in6_addr addr)
+g_sockaddr_inet6_set_address(GSockAddr *s, struct in6_addr *addr)
 {
-  g_sockaddr_inet6_get_sa(s)->sin6_addr = addr;
+  g_sockaddr_inet6_get_sa(s)->sin6_addr = *addr;
 }
 
 /**



Diffing against syslog-ng--mainline--2.0
TLA version: '1.3.3-2'
Running command 'tla changes --diffs -d /home/bazsi/zwa/tla/devel at balabit.hu--other-1/syslog-ng--mainline--2.0 devel at balabit.hu--other-1/syslog-ng--mainline--2.0', cwd=''


More information about the syslog-ng mailing list