├── README.md └── gre-keepalive.pl /README.md: -------------------------------------------------------------------------------- 1 | # linux-gre-keepalive 2 | Userspace daemon in perl to handle Cisco GRE keepalives. Works in Linux, should work in any *nix derivative 3 | 4 | Requires Net::Pcap, NetPacket::IP, and Proc::Daemon 5 | 6 | (all 3 have stable debian perl packages in the standard repositories) 7 | 8 | Usage: 9 | 10 | sysctl -w net.ipv4.ip_forward=1 11 | 12 | sysctl -w net.ipv6.conf.all.forwarding=1 13 | 14 | ip tunnel add mytunnel mode gre remote x.x.x.x local y.y.y.y ttl 255 pmtudisc 15 | 16 | ip link set mytunnel up 17 | 18 | ./gre-keepalive.pl mytunnel 19 | 20 | 21 | This daemon does not initiate keepalive packets, but does look for ones sent by the originating system and redirects them as a standard Cisco router would, thus causing the GRE tunnel to go up/up, and causing it to go up/down if connectivity is lost. 22 | -------------------------------------------------------------------------------- /gre-keepalive.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Net::Pcap; 7 | use Proc::Daemon; 8 | use Socket; 9 | 10 | Proc::Daemon::Init; 11 | 12 | socket(my $socket, AF_INET, SOCK_RAW, 255) || die $!; 13 | setsockopt($socket, 0, 1, 1); 14 | 15 | my $dev = $ARGV[0]; 16 | my $err; 17 | my $pcap = Net::Pcap::open_live($dev, 1024, 0, 0, \$err); 18 | 19 | my $filter = "proto gre"; 20 | my $filter_t; 21 | if (Net::Pcap::compile($pcap, \$filter_t, $filter, 1, 0) == -1) { 22 | die "Unable to compile filter string '$filter'\n"; 23 | } 24 | Net::Pcap::setfilter($pcap, $filter_t); 25 | 26 | Net::Pcap::loop($pcap, -1, \&process_packet, $socket); 27 | 28 | Net::Pcap::close($pcap); 29 | 30 | sub process_packet { 31 | my ($socket, $header, $packet) = @_; 32 | 33 | # Strip the "cooked capture" header. 34 | $packet = unpack("x16a*", $packet); 35 | 36 | my $dest_ip = unpack("x16a4", $packet); 37 | if (!send($socket, $packet, 0, pack_sockaddr_in(0, $dest_ip))) { 38 | die "Couldn't send packet: $!"; 39 | } 40 | } 41 | 42 | --------------------------------------------------------------------------------