Skip to content

Commit

Permalink
added syslog-multicast client to contrib
Browse files Browse the repository at this point in the history
  • Loading branch information
Balazs Scheidler committed Apr 14, 2007
1 parent 29bcd9f commit 009401c
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 1 deletion.
15 changes: 15 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@
# arch-tag: [email protected]/syslog-ng--mainline--2.0
#

2006-10-06 11:49:45 GMT Balazs Scheidler <[email protected]> patch-83

Summary:
added syslog-multicast client to contrib
Revision:
syslog-ng--mainline--2.0--patch-83


new files:
contrib/.arch-ids/syslog-mc.id contrib/syslog-mc

modified files:
ChangeLog contrib/README


2006-09-14 12:35:49 GMT Balazs Scheidler <[email protected]> patch-82

Summary:
Expand Down
3 changes: 2 additions & 1 deletion contrib/README
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ syslog-ng.conf.doc - sample configuration file with inline documentation as comm
syslog-ng.vim - vim syntax file for syslog-ng.conf
syslog2ng - script to convert old syslog.conf to syslog-ng.conf
relogger.pl - script to replay syslog messages at the original rate
fedora-packaging - directory containing files related to Fedora packaging
fedora-packaging - directory containing files related to Fedora packaging
syslog-mc - syslog multicast client
226 changes: 226 additions & 0 deletions contrib/syslog-mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
#!/usr/bin/perl
#
# syslog-mc:
# This perl script is to be used in conjuction with syslog-ng and it's
# multicast feature.
#
# All you need to do is run the program, pass an IPv4 or IPv6 multicast
# address as the first parameter and the script will 'tune in' to the syslog
# multicast group and display the syslog lines.
#
# This helps no end if you want to write local trigger scripts or have a live
# view of some daemon without actually having to be logged into the central
# syslog server cluster.
#
# One note to bear in mind is that if you send you logs in the multicast group
# to a port number below 1024 then you will need root privileges to run this
# script. It's probably a good idea to send your logs to a port number above
# 1024 so that you do not need to run things as root. Another recommendation
# is to remember to 'seperate' your group addresses by thirty two IP's (for
# IPv4) so that you do not receive any unwanted, although it's harmless and
# filtered, extra traffic.
#
# When using the script, you can run it standalone and it will simply print the
# syslog messages to STDOUT however you might prefer to pipe it into grep or
# some other tool, so to print all the lines containing the word 'cheese':
#
# $ ./syslog-mc 239.194.253.8 5514 | grep cheese
#
# --
# Maintained by Alexander Clouter <[email protected]>
# Written/Copyright 2006 by Alexander Clouter <[email protected]>
#
# This software may be used and distributed according to the terms
# of the version two of the GNU General Public License, incorporated herein by
# reference.
#
use strict;
use warnings;

my $running = 1;

use sigtrap 'handler' => sub { $running = 0 }, qw( INT );

# under debian all these dependencies can be met with:
# aptitude install libnet-ip-perl libsocket6-perl libio-socket-inet6-perl libparse-syslog-perl
use Net::IP;
use Socket;
use Socket6;
use IO::Socket::INET6;
# we use IO::Select to avoid the nasty blocking nature of Parse::Syslog
use IO::Select;
use Parse::Syslog;
use POSIX;

# enable debugging?
use constant DEBUG => 0;
if ( DEBUG ) {
use Data::Dumper;
}

my ( $mcGroup, $port ) = ( $ARGV[0], $ARGV[1] );

unless ( $mcGroup ) {
print <<EOF;
Use: syslog-mc.pl <mcast-addr> [port]
EOF
exit 0;
}

$mcGroup =~ s/\s*(.+)\s*/$1/;

my $ip = Net::IP->new($mcGroup)
|| die 'First parameter is not a valid IP address';
if ( $ip->version == 4 ) {
unless ( Net::IP->new('224.0.0.0/4')->overlaps($ip) != $Net::IP::IP_NO_OVERLAP ) {
print STDERR "IPv4 address given is not a multicast address\n";
exit 1;
}
}
elsif ( $ip->version == 6 ) {
unless ( Net::IP->new('ff::/120')->overlaps($ip) != $Net::IP::IP_NO_OVERLAP ) {
print STDERR "IPv6 address given is not a multicast address\n";
exit 1;
}
}
else {
print STDERR "Unknown IP Version\n";
exit 1;
}

if ( $port ) {
$port =~ s/\s*(.+)\s*/$1/;

if ( $port =~ /^\d+$/ ) {
unless ( $port > 0 && $port < 65536 ) {
print STDERR "Invalid port number\n";
exit 1;
}
}
}
else {
$port = 514;

print STDERR "No port number given, assuming 514\n"
if ( DEBUG );
}

my $sock = &subscribe($mcGroup, $port);
unless ( $sock ) {
print STDERR "Unable to open socket so bombing out\n";
exit 1;
}

my $parser = Parse::Syslog->new($sock, arrayref => 1);

my $selectPoll = IO::Select->new;
$selectPoll->add($sock);

while ( $running ) {
my ( $select_set ) = IO::Select->select($selectPoll, undef, undef);

foreach my $fh ( @$select_set ) {
if ( $fh == $sock ) {
if ( $sock->eof ) {
$running = 0;
next;
}

my $sl = $parser->next;

my $timestamp = POSIX::strftime '%b %e %T', gmtime($sl->[0]);
my $pid = ( $sl->[3] ) ? $sl->[3] : 'na';

print "$timestamp " . $sl->[1] . ' ' . $sl->[2] . "[$pid]: " . $sl->[4] . "\n";
}
}
}

$selectPoll->remove($sock);

&unsubscribe($sock);

exit 0;

sub subscribe {
my $mcGroup = shift;
my $port = shift;

print STDERR "Trying to join group $mcGroup: "
if ( DEBUG );

my @res = getaddrinfo $mcGroup, $port, AF_UNSPEC, SOCK_DGRAM;
my $sock = IO::Socket::INET6->new(
Domain => $res[0],
LocalAddr => $mcGroup,
Proto => 'udp',
Type => SOCK_DGRAM,
LocalPort => $port,
ReuseAddr => 1 ) || print STDERR "Can't bind : $@\n";
unless ( $sock && ref $sock eq 'IO::Socket::INET6' ) {
print STDERR "Unable to open socket! If using a port number below 1024 you need to be root\n";
return;
}

my $joinStatus;
if ( $sock->sockdomain == AF_INET ) {
# struct ip_mreq <netinet/in.h>
my $mreq = pack 'a4 a4', inet_pton(AF_INET, $mcGroup), INADDR_ANY;
# IP_ADD_MEMBERSHIP = 35
$joinStatus = setsockopt $sock, IPPROTO_IP, 35, $mreq;
}
elsif ( $sock->sockdomain == AF_INET6 ) {
# struct ipv6_mreq <netinet/in.h>
my $mreq6 = pack 'a16 N', inet_pton(AF_INET6, $mcGroup), 0;
# IPV6_ADD_MEMBERSHIP = 20
$joinStatus = setsockopt $sock, IPPROTO_IPV6, 20, $mreq6;
}
else {
print STDERR "unknown IP version, "
if ( DEBUG );
$joinStatus = -1;
}

if ( $joinStatus == -1 ) {
print STDERR "unable to ADD_MEMBERSHIP for $mcGroup\n"
if ( DEBUG );
close $sock;
return;
}

print STDERR "successful\n"
if ( DEBUG );

return $sock;
}

sub unsubscribe {
my $sock = shift;

my $mcGroup = $sock->sockhost;

print STDERR "Leaving group $mcGroup: "
if ( DEBUG );

my $leaveStatus;
if ( $sock->sockdomain == AF_INET ) {
my $mreq = pack 'a4 a4', inet_pton(AF_INET, $mcGroup), INADDR_ANY;
# IP_DROP_MEMBERSHIP = 36
$leaveStatus = setsockopt $sock, IPPROTO_IP, 36, $mreq;
}
else {
my $mreq6 = pack 'a16 N', inet_pton(AF_INET6, $mcGroup), 0;
# IPV6_DROP_MEMBERSHIP = 21
$leaveStatus = setsockopt $sock, IPPROTO_IPV6, 21, $mreq6;
}

if ( $leaveStatus == -1 ) {
print STDERR "warning, unable to DROP_MEMBERSHIP for $mcGroup..."
if ( DEBUG );
}

close $sock;

print STDERR "done\n"
if ( DEBUG );
}

0 comments on commit 009401c

Please sign in to comment.