commit
c593cf1bd8
21 changed files with 2797 additions and 0 deletions
@ -0,0 +1,11 @@ |
|||
debian/.debhelper |
|||
debian/debhelper-build-stamp |
|||
debian/files |
|||
debian/rrqnet.debhelper.log |
|||
debian/rrqnet.substvars |
|||
debian/rrqnet |
|||
rrqnet |
|||
rrqnet-cron.sh.8 |
|||
rrqnet-cron.sh.8.html |
|||
rrqnet.8 |
|||
rrqnet.8.html |
@ -0,0 +1,59 @@ |
|||
SBINDIR = $(DESTDIR)/usr/local/sbin |
|||
ETCDIR = $(DESTDIR)/etc/rrqnet |
|||
MAN1DIR = $(DESTDIR)/usr/local/share/man/man1 |
|||
MAN8DIR = $(DESTDIR)/usr/local/share/man/man8 |
|||
|
|||
SBINFILES = rrqnet rrqnet-cron.sh |
|||
ETCFILES = set-source-route.sh |
|||
MAN1FILES = |
|||
MAN8FILES = rrqnet.8 rrqnet-cron.sh.8 |
|||
HTMLDOC = $(MAN8FILES:%=%.html) |
|||
|
|||
all: $(SBINFILES) $(ETCFILES) $(MAN1FILES) $(MAN8FILES) $(HTMLDOC) |
|||
|
|||
$(HTMLDOC): %.html: %.adoc |
|||
asciidoc -bhtml $^ |
|||
|
|||
$(MAN8FILES): %: %.adoc |
|||
a2x -d manpage -f manpage $^ |
|||
|
|||
rrqnet: LDFLAGS += -lpthread |
|||
rrqnet: rrqnet.c htable.h htable.c sockaddr.h queue.h queue.c |
|||
|
|||
rrqnet.E: rrqnet.c htable.c |
|||
$(CC) -W -Wall $^ > $@ |
|||
|
|||
COMPILEOPTS = -g -W -Wall |
|||
#COMPILEOPTS = -pg -no-pie -g -DGPROF
|
|||
|
|||
$(filter-out %.sh,$(SBINFILES)): %: %.c |
|||
$(CC) $(COMPILEOPTS) -static -o $@ $^ $(LDFLAGS) |
|||
|
|||
.PHONY: clean |
|||
clean: |
|||
rm -f $(filter-out %.sh,$(SBINFILES)) |
|||
|
|||
# Installation targets
|
|||
|
|||
INSTALLTARGETS = $(addprefix $(SBINDIR)/,$(SBINFILES)) |
|||
INSTALLTARGETS += $(addprefix $(ETCDIR)/,$(ETCFILES)) |
|||
INSTALLTARGETS += $(addprefix $(MAN1DIR)/,$(MAN1FILES)) |
|||
INSTALLTARGETS += $(addprefix $(MAN8DIR)/,$(MAN8FILES)) |
|||
|
|||
#INSTALL = install -b -S orig
|
|||
INSTALL = install |
|||
|
|||
$(addprefix $(ETCDIR)/,conf.d keys): |
|||
mkdir -p $@ |
|||
|
|||
$(ETCCFG)/cron.sh: rrqnet-cron.sh |
|||
$(INSTALL) -D -T $< $@ |
|||
|
|||
$(SBINDIR)/% $(ETCDIR)/% $(MAN1DIR)/% $(MAN8DIR)/%: % |
|||
$(INSTALL) -D -T $< $@ |
|||
|
|||
install: $(INSTALLTARGETS) |
|||
|
|||
BUILDPACKAGE = -us -uc --build=full |
|||
deb: |
|||
PREFIX= INCLUDE_PREFIX=/usr dpkg-buildpackage $(BUILDPACKAGE) |
@ -0,0 +1,5 @@ |
|||
rrqnet (0.1) experimental; urgency=medium |
|||
|
|||
* Initial release (restart from udptap=0.2.5) |
|||
|
|||
-- Ralph Ronnquist <ralph.ronnquist@gmail.com> Wed, 17 Jun 2020 20:34:04 +1000 |
@ -0,0 +1 @@ |
|||
9 |
@ -0,0 +1,19 @@ |
|||
Source: rrqnet |
|||
Section: admin |
|||
Priority: optional |
|||
Maintainer: Ralph Ronnquist <ralph.ronnquist@gmail.com> |
|||
Build-Depends: debhelper (>= 9), asciidoc, docbook-xml, libxslt1-dev, xsltproc, |
|||
docbook-xsl |
|||
Standards-Version: 3.9.8 |
|||
Homepage: <insert the upstream URL, if relevant> |
|||
Vcs-Git: https://gitea.devuan.dev/devuan/rrqnet.git |
|||
|
|||
Package: rrqnet |
|||
Architecture: any |
|||
Depends: ${shlibs:Depends}, ${misc:Depends}, bash, bridge-utils, iproute2, |
|||
lsof, net-tools, util-linux |
|||
Description: Packet tunneling over UDP, multiple channels |
|||
rrqnet is a bi-directional networking plug that channels packets |
|||
between a UDP port and either or a tap interface or standard |
|||
input/output. It is configured on the command line by declarations of |
|||
the remotes it may communicate with. |
@ -0,0 +1,22 @@ |
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ |
|||
Upstream-Name: rrqnet |
|||
Source: <url://example.com> |
|||
|
|||
Files: debian/* |
|||
Copyright: 2020 Ralph Ronnquist <ralph@ascii> |
|||
License: GPL-2+ |
|||
This package is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; either version 2 of the License, or |
|||
(at your option) any later version. |
|||
. |
|||
This package is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
. |
|||
You should have received a copy of the GNU General Public License |
|||
along with this program. If not, see <https://www.gnu.org/licenses/> |
|||
. |
|||
On Debian systems, the complete text of the GNU General |
|||
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". |
@ -0,0 +1,27 @@ |
|||
#!/usr/bin/make -f |
|||
# See debhelper(7) (uncomment to enable) |
|||
# output every command that modifies files on the build system. |
|||
#export DH_VERBOSE = 1 |
|||
|
|||
|
|||
# see FEATURE AREAS in dpkg-buildflags(1) |
|||
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all |
|||
|
|||
# see ENVIRONMENT in dpkg-buildflags(1) |
|||
# package maintainers to append CFLAGS |
|||
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic |
|||
# package maintainers to append LDFLAGS |
|||
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed |
|||
|
|||
|
|||
%: |
|||
dh $@ |
|||
|
|||
|
|||
# dh_make generated override targets |
|||
# This is example for Cmake (See https://bugs.debian.org/641051 ) |
|||
#override_dh_auto_configure: |
|||
# dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) |
|||
|
|||
override_dh_usrlocal: |
|||
true |
@ -0,0 +1 @@ |
|||
3.0 (native) |
@ -0,0 +1,22 @@ |
|||
dh_update_autotools_config |
|||
dh_auto_configure |
|||
dh_auto_build |
|||
dh_auto_test |
|||
dh_prep |
|||
dh_auto_install |
|||
dh_installdocs |
|||
dh_installchangelogs |
|||
dh_perl |
|||
dh_usrlocal |
|||
dh_link |
|||
dh_strip_nondeterminism |
|||
dh_compress |
|||
dh_fixperms |
|||
dh_missing |
|||
dh_strip |
|||
dh_makeshlibs |
|||
dh_shlibdeps |
|||
dh_installdeb |
|||
dh_gencontrol |
|||
dh_md5sums |
|||
dh_builddeb |
@ -0,0 +1,2 @@ |
|||
misc:Depends= |
|||
misc:Pre-Depends= |
@ -0,0 +1,135 @@ |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include "htable.h" |
|||
|
|||
//// Generic hash table implementation
|
|||
|
|||
// Determine the index for a key. On match, it returns the index into
|
|||
// the table. On mismatch it returns -i-1 for the first free spot
|
|||
// where the keyed element would fit.
|
|||
static int htindex(htable *table,unsigned char *key) { |
|||
if ( table->data == 0 ) { |
|||
table->data = calloc( 256, sizeof( unsigned char* ) ); |
|||
table->size = 256; |
|||
} |
|||
unsigned int hash = (*table->hashcode)( table, key ) % table->size; |
|||
unsigned int i = hash; |
|||
int hole = -1; |
|||
for ( ;; ) { |
|||
unsigned char *x = table->data[ i++ ]; |
|||
if ( x == 0 ) { |
|||
return ( hole >= 0 )? -hole : - (int) i; |
|||
} |
|||
if ( x == (unsigned char *)1 ) { |
|||
if ( hole < 0 ) { |
|||
hole = i; |
|||
} |
|||
} else if ( memcmp( x + table->offset, key, table->esize ) == 0 ) { |
|||
return i-1; |
|||
} |
|||
if ( i >= table->size ) { |
|||
i = 0; |
|||
} |
|||
if ( i == hash ) { |
|||
break; |
|||
} |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
// Find the keyed element, and assign the x pointer, or assign 0.
|
|||
// Returns 1 if element is found and 0 otherwise.
|
|||
int htfind(htable *table,void *key,unsigned char **x) { |
|||
pthread_mutex_lock( &table->lock ); |
|||
int i = htindex( table, key ); |
|||
if ( i < 0 ) { |
|||
*x = 0; |
|||
pthread_mutex_unlock( &table->lock ); |
|||
return 0; |
|||
} |
|||
*x = table->data[ i ]; |
|||
pthread_mutex_unlock( &table->lock ); |
|||
return 1; |
|||
} |
|||
|
|||
// Forward
|
|||
static void htgrow(htable *table); |
|||
|
|||
// Add the given element.
|
|||
void htadd(htable *table,unsigned char *p) { |
|||
pthread_mutex_lock( &table->lock ); |
|||
if ( table->fill >= table->size / 2 ) { |
|||
htgrow( table ); |
|||
} |
|||
int i = htindex( table, p + table->offset ); |
|||
if ( i < 0 ) { |
|||
i = -i - 1; |
|||
if ( table->data[ i ] != 0 ) { |
|||
table->holes--; |
|||
} else { |
|||
table->fill++; |
|||
} |
|||
} else { |
|||
// There is a match already what to do?
|
|||
} |
|||
table->data[ i ] = p; |
|||
pthread_mutex_unlock( &table->lock ); |
|||
} |
|||
|
|||
// Return the next element starting at i, or 0 if there are no more.
|
|||
// Also increment the index to be of the element + 1, or -1 if there
|
|||
// are no more elements.
|
|||
static unsigned char *htnext(htable *table,int *i) { |
|||
if ( *i < 0 ) { |
|||
return 0; |
|||
} |
|||
unsigned char **p = table->data + *i; |
|||
unsigned char **e = table->data + table->size; |
|||
for ( ; p < e; p++ ) { |
|||
(*i) += 1; |
|||
if ( *p != 0 || *p != (unsigned char*)1 ) { |
|||
return *p; |
|||
} |
|||
} |
|||
(*i) = -1; |
|||
return 0; |
|||
} |
|||
|
|||
static void htrehash(htable *table,unsigned int size) { |
|||
htable old = *table; |
|||
table->data = calloc( size, sizeof( unsigned char * ) ); |
|||
table->size = size; |
|||
table->fill = 0; |
|||
table->holes = 0; |
|||
int i = 0; |
|||
unsigned char *p; |
|||
while ( ( p = htnext( &old, &i ) ) != 0 ) { |
|||
htadd( table, p ); |
|||
} |
|||
free( old.data ); |
|||
} |
|||
|
|||
static void htgrow(htable *table) { |
|||
if ( table->data == 0 ) { |
|||
table->data = calloc( 256, sizeof( unsigned char * ) ); |
|||
table->size = 256; |
|||
table->fill = 0; |
|||
table->holes = 0; |
|||
return; |
|||
} |
|||
htrehash( table, table->size << 8 ); |
|||
} |
|||
|
|||
// Delete the given element.
|
|||
void htdelete(htable *table,unsigned char *p) { |
|||
pthread_mutex_lock( &table->lock ); |
|||
int i = htindex( table, p + table->offset ); |
|||
if ( i >= 0 ) { |
|||
table->data[ i ] = (unsigned char *)1; |
|||
table->holes += 1; |
|||
if ( table->holes > table->fill / 2 ) { |
|||
htrehash( table, table->size ); |
|||
} |
|||
} |
|||
pthread_mutex_unlock( &table->lock ); |
|||
} |
@ -0,0 +1,71 @@ |
|||
// A hashtable implementation with vectorized hashcode function.
|
|||
//
|
|||
// A hashtable is array of pointers, or the values 0 and 1, which mark
|
|||
// unused and cleared slots respectively.
|
|||
//
|
|||
// Hash collision is handled by using the next usused or cleared slot
|
|||
// by increasing, cycled indexing. An addition when the fill exceeds
|
|||
// half the size causes a rehash into a new, double size table,
|
|||
// without any cleared slots (i.e., the fill might be reduced after
|
|||
// rehash, due to cleared slots).
|
|||
//
|
|||
// The fill count includes cleared entries, which counts deleted
|
|||
// entries. A deletion that makes the number of cleared slots to
|
|||
// exceed half the fill also causes a rehash into a new, same size
|
|||
// table, without any cleared clots.
|
|||
//
|
|||
// The data elements have a key part, which is a contiguous portion of
|
|||
// bytes at a given offset. The offset and size of the key are the
|
|||
// same for all elements.
|
|||
//
|
|||
#ifndef HTABLE_H |
|||
#define HTABLE_H |
|||
|
|||
#define __USE_GNU 1 |
|||
#include <pthread.h> |
|||
|
|||
// The hashtable head data structure: htable
|
|||
typedef struct _htable { |
|||
unsigned char **data; // array of entries
|
|||
unsigned int size; // total array size
|
|||
unsigned int offset; // offset into elements for the key part
|
|||
unsigned int esize; // byte size of the key part
|
|||
unsigned int fill; // number of added elements
|
|||
unsigned int holes; // number of deleted
|
|||
int (*hashcode)(struct _htable *table,unsigned char *key); |
|||
pthread_mutex_t lock; |
|||
} htable; |
|||
|
|||
// Determine the index for a key. On match, it returns the index into
|
|||
// the table. On mismatch it returns -i-1 for the first free spot
|
|||
// where the keyed element would fit.
|
|||
//int htindex(htable *table,unsigned char *key);
|
|||
|
|||
// Find the keyed element, and assign the x pointer, or assign 0.
|
|||
// Returns 1 if element is found and 0 otherwise.
|
|||
int htfind(htable *table,void *key,unsigned char **x); |
|||
|
|||
// Add the given element.
|
|||
void htadd(htable *table,unsigned char *p); |
|||
|
|||
// Return the next element starting at i, or 0 if there are no more.
|
|||
// Also increment the index to be of the element + 1, or -1 if there
|
|||
// are no more elements.
|
|||
//unsigned char *htnext(htable *table,int *i);
|
|||
|
|||
// Delete the given element.
|
|||
void htdelete(htable *table,unsigned char *p); |
|||
|
|||
// Special macro for htable initialization giving the record type, the
|
|||
// key field and hashcode funtion.
|
|||
// type = (base) data type for the elements
|
|||
// member = the key field
|
|||
// hashcodefn = function computing hashcode for a key
|
|||
// assigns .compare = memcmp
|
|||
#define HTABLEINIT(type,member,hashcodefn) \ |
|||
{ .data = 0, .size = 0, .fill = 0, \ |
|||
.holes = 0, .offset = offsetof( type, member ), \ |
|||
.esize = sizeof( ((type *)0)->member ), .hashcode = hashcodefn, \ |
|||
.lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } |
|||
|
|||
#endif // HTABLE_H
|
@ -0,0 +1,71 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include "queue.h" |
|||
|
|||
void Queue_addItem(Queue *list,QueueItem *item) { |
|||
if ( pthread_mutex_lock( &list->mutex ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
item->next = 0; // just in case
|
|||
if ( list->last ) { |
|||
list->last->next = item; |
|||
} else { |
|||
list->head = item; |
|||
} |
|||
list->last = item; |
|||
if ( sem_post( &list->count ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
if ( pthread_mutex_unlock( &list->mutex ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
} |
|||
|
|||
QueueItem *Queue_getItem(Queue *list) { |
|||
QueueItem *item; |
|||
if ( sem_wait( &list->count ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
if ( pthread_mutex_lock( &list->mutex ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
item = list->head; |
|||
list->head = item->next; |
|||
if ( list->head == 0 ) { |
|||
list->last = 0; |
|||
} |
|||
if ( pthread_mutex_unlock( &list->mutex ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
return item; |
|||
} |
|||
|
|||
void Queue_initialize(Queue *list,int n,size_t size) { |
|||
if ( pthread_mutex_lock( &list->mutex ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
if ( list->head == 0 ) { |
|||
int i = 0; |
|||
for ( ; i < n; i++ ) { |
|||
QueueItem *x = (QueueItem *) calloc( 1, size ); |
|||
if ( list->head ) { |
|||
list->last->next = x; |
|||
} else { |
|||
list->head = x; |
|||
} |
|||
list->last = x; |
|||
} |
|||
sem_init( &list->count, 0, n ); |
|||
} |
|||
if ( pthread_mutex_unlock( &list->mutex ) ) { |
|||
perror( "FATAL" ); |
|||
exit( 1 ); |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
#ifndef queue_H |
|||
#define queue_H |
|||
|
|||
#include "sockaddr.h" |
|||
#include <semaphore.h> |
|||
#include <pthread.h> |
|||
|
|||
typedef struct _QueueItem { |
|||
struct _QueueItem *next; |
|||
char data[]; |
|||
} QueueItem; |
|||
|
|||
typedef struct _Queue { |
|||
QueueItem *head; |
|||
QueueItem *last; |
|||
sem_t count; |
|||
pthread_mutex_t mutex; |
|||
} Queue; |
|||
|
|||
extern void Queue_addItem(Queue *list,QueueItem *item); |
|||
extern QueueItem *Queue_getItem(Queue *list); |
|||
extern void Queue_initialize(Queue *list,int n,size_t size); |
|||
|
|||
#endif |
|||
|
@ -0,0 +1,19 @@ |
|||
About rrqnet |
|||
============ |
|||
|
|||
This repository holds the sources for *rrqnet*, which concern VPN |
|||
building over UDP transport. It operates at Ethernet level, which |
|||
means it transports both ipv4 and ipv6, and it can thus be used for |
|||
ipv6 over ipv4 tunneling, or ipv4 tunneling over ipv6, as well as ipv4 |
|||
VPN or ipv6 VPN. |
|||
|
|||
MAN PAGES |
|||
--------- |
|||
* link:rrqnet.8.adoc[The rrqnet man page] |
|||
* link:rrqnet-cron.sh.8.adoc[The rrqnet-cron.sh man page] |
|||
|
|||
Devuan Packages |
|||
--------------- |
|||
|
|||
* The *rrqnet* package contains the binaries and their man pages, |
|||
as well as the utility scripting. |
@ -0,0 +1,36 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Cron-driven bot to start a rrqnet cables or switch unless already up |
|||
|
|||
RRQNET=/usr/local/sbin/rrqnet |
|||
|
|||
function start-switch() { |
|||
. $1 |
|||
exec $RRQNET $VERBOSE -4 $PORT ${VPN[@]} |
|||
} |
|||
|
|||
function start-cable() { |
|||
. $1 |
|||
ip link show dev $TAP > /dev/null || \ |
|||
{ ip tuntap add $TAP mode tap ; ip link set dev $TAP up ; } |
|||
[ -z "$MAC" ] || ifconfig $TAP | grep -q "ether $MAC" || \ |
|||
ifconfig $TAP hw ether $MAC |
|||
[ -z "$IP" ] || ip addr show dev $TAP | grep -q $IP || \ |
|||
ip addr add $IP dev $TAP |
|||
[ -z "$BR" ] || brctl show | grep -q $TAP || \ |
|||
brctl addif $BR $TAP |
|||
exec $RRQNET $VERBOSE -4 ${OPTIONS[@]} -t $TAP $PORT ${VPN[@]} |
|||
} |
|||
|
|||
for CABLE in $* ; do |
|||
CONF=/etc/rrqnet/conf.d/$CABLE.conf |
|||
eval $(grep ^PORT= $CONF) |
|||
lsof -i :$PORT > /dev/null && continue |
|||
eval $(grep ^TAP= $CONF) |
|||
LOG=/tmp/$CABLE.log |
|||
if [ -z "$TAP" ] ; then |
|||
( start-switch $CONF < /dev/null >> $LOG 2>&1 & ) |
|||
else |
|||
( start-cable $CONF /dev/null >> $LOG 2>&1 & ) |
|||
fi |
|||
done |
@ -0,0 +1,125 @@ |
|||
rrqnet-cron.sh(8) |
|||
================= |
|||
:doctype: manpage |
|||
:revdate: {sys:date "+%Y-%m-%d %H:%M:%S"} |
|||
|
|||
NAME |
|||
---- |
|||
rrqnet-cron.sh - Management script to uphold a *rrqnet* plug. |
|||
|
|||
SYNOPSIS |
|||
-------- |
|||
*rrqnet-cron.sh* _vpn_ ... |
|||
|
|||
DESCRIPTION |
|||
----------- |
|||
|
|||
*rrqnet-cron.sh* is a management script for upholding a *rrqnet* plug |
|||
for a nominated VPN confguration. The given _vpn_, or several, is the |
|||
pathname relative to the configuration root directory and with a |
|||
+.conf+ extension added, as in +/etc/rrqnet/conf.d/+*vpn*+.conf+. |
|||
|
|||
The following is a configuration file example: |
|||
|
|||
./etc/rrqnet/conf.d/tap0-client.conf |
|||
---- |
|||
TAP=tap0 |
|||
MAC=02:00:00:00:01:00 |
|||
BR= |
|||
IP=192.168.10.2 |
|||
PORT=1500 |
|||
OPTIONS=( ) |
|||
VPN=( 10.61.4.72:2020=/etc/rrqnet/keys/example.key ) |
|||
VERBOSE=-v |
|||
---- |
|||
|
|||
* The `TAP` assignment names the tap interface to use. |
|||
* The optional MAC assignment, if provided, tells *rrqnet-cron.sh* to |
|||
set the Ethernet address of the tap interface as given. |
|||
* The optional `BR` assignment, if provided, tells *rrqnet-cron.sh* |
|||
to add the tap interface to the bridge upon start. |
|||
* The optional `IP` assignment, if provided, tells *rrqnet-cron.sh* |
|||
how to configure the tap interface when it is brought up. If empty, |
|||
the tap interface is brought up without confgiured IP address. |
|||
* The `PORT` assignment declares which port *rrqnet* should listen |
|||
on. It will listen on that port on all interfaces. |
|||
* The optional `OPTIONS` is intended for the -B and -T options to |
|||
*rrqnet*. |
|||
* The `VPN` assignment declares the remotes for *rrqnet*. |
|||
* The optional `VERBOSE` assignment, which must be `-v`, `-vv` or |
|||
`-vvv` unless empty, defines the verbosity level for *rrqnet*. |
|||
|
|||
The above example declares an uplink remote at example ivp4 address |
|||
`10.61.4.72`, port 2020, and using a transport encryption key. The |
|||
remote host at that IP address should have a corresponding |
|||
declaration, perhaps as follows: |
|||
|
|||
./etc/rrqnet/conf.d/tap0-server.conf |
|||
---- |
|||
TAP=tap0 |
|||
IP=192.168.10.1 |
|||
PORT=2020 |
|||
VPN=( 0.0.0.0/0=/etc/rrqnet/keys/example.key ) |
|||
---- |
|||
|
|||
That "server" declaration is allows UDP packets from any host and |
|||
port, requiring the them to use the same transport encryption key. The |
|||
*rrqnet* "server" plug then works like a switch, which forwards |
|||
packets between connections as well as to and from the tap. Actual |
|||
connections are identified by the remote MAC addresses, and it's up to |
|||
the remote ends to resolve IP addresses to the MAC addresses on the |
|||
virtual net, which in the example would be +192.168.10.0/24+. |
|||
|
|||
The +VPN+ variable may have multiple remote declarations, and include |
|||
both up-links and down-links, with or without thransport encryption |
|||
keys. E.g., |
|||
---- |
|||
VPN=( 192.168.0.0/16:1400 10.61.4.72:2020=/sec/example.key ) |
|||
---- |
|||
|
|||
A VPN assignment like that would both allow remotes in IP range |
|||
+192.168.0.0/16+, port 1400, without transport key, and have an |
|||
up-link to that example "server" remote above (though, for the sake of |
|||
example, having its key residing at a different pathname). |
|||
|
|||
crontab set up |
|||
~~~~~~~~~~~~~~ |
|||
|
|||
The script *rrqnet-cron.sh* is intended to be set up in *crontab*, by |
|||
a line as follows: |
|||
---- |
|||
* * * * * /usr/local/sbin/rrqnet-cron.sh tap0-client |
|||
---- |
|||
|
|||
By that *crontab* line, the script will be invoked every minute for |
|||
unsuting that the *rrqnet* plug declared by |
|||
+/etc/rrqnet/conf.d/tap0-client.conf+, is still running, and otherwise |
|||
start or restart it. |
|||
|
|||
The script uses a lock file that gets named by the `TAP` assignment, |
|||
as in +/var/lock/rrqnet-tap0+, for the example. This allows an |
|||
alternative management set up, for a *rrqnet* cable to be maintained |
|||
with an almost immediate restart when it goes down, through a simple |
|||
loop like the following: |
|||
---- |
|||
# while flock /var/lock/rrqnet-tap0 ; do rrqnet-cron.sh tap0 done |
|||
---- |
|||
That control loop would be waiting for the running *rrqnet* to release |
|||
the file lock on +/var/lock/rrqnet-tap0+, and then, almost immediately |
|||
restart the virtual cable. |
|||
|
|||
NOTES |
|||
----- |
|||
|
|||
Note that *rrqnet-cron.sh* sources the configuration file and exits |
|||
after optionally spawning a *rrqnet* daemon. On may therefore safely |
|||
just change the cable set up, and kill *rrqnet* in order apply that |
|||
changed set up. |
|||
|
|||
SEE ALSO |
|||
-------- |
|||
*rrqnet(8)* - Packet tunneling over UDP, multiple channels |
|||
|
|||
AUTHOR |
|||
------ |
|||
Ralph Rönnquist <ralph.ronnquist@gmail.com> |
@ -0,0 +1,444 @@ |
|||
rrqnet(8) |
|||
========= |
|||
:doctype: manpage |
|||
:revdate: {sys:date "+%Y-%m-%d %H:%M:%S"} |
|||
:COLON: : |
|||
:EQUALS: = |
|||
|
|||
NAME |
|||
---- |
|||
rrqnet - Packet tunneling over UDP, multiple channels |
|||
|
|||
SYNOPSIS |
|||
-------- |
|||
*rrqnet* [ OPTIONS ] _port_ ( _remote_ [*-i* _mac_]* )* |
|||
|
|||
DESCRIPTION |
|||
----------- |
|||
*rrqnet* is a bi-directional networking plug that channels Ethernet |
|||
packets between a UDP port and either a tap interface or standard |
|||
input/output. It is configured on the command line by declarations of |
|||
the remotes it may communicate with. |
|||
|
|||
OPTIONS |
|||
------- |
|||
|
|||
Note that any options must be given in the fixed order: |
|||
|
|||
[-v] [-4] [-B n] [-T n] [-m mcast] [-t tap] |
|||
|
|||
*-v*:: |
|||
|
|||
This tells *rrqnet* to log its operation on +stderr+. Use *-vv* to |
|||
also see logs about connections and messaging, or *-vvv* for *rrqnet* |
|||
to be insanely verbose on +stderr+ about virtually everything. |
|||
|
|||
*-4*:: |
|||
|
|||
This directs *rrqnet* to use an ipv4-only socket for its UDP. By |
|||
default it opens a dual ipv4/ipv6 socket and internally it then uses |
|||
address mapping for ipv4 (i.e. the ::ffff/96 prefix). |
|||
|
|||
*-B* _n_:: |
|||
|
|||
This sets the number of receive buffers *rrqnet* should use. The |
|||
default is computed to be twice the number of dispatch threads (see |
|||
*-T* below). Receive buffers are pre-allocated and recycled. |
|||
|
|||
*-T* _n_:: |
|||
|
|||
This sets the number of dispatch threads *rrqnet* should use. The |
|||
default is 5. The (additional) main thread handles packet reception, |
|||
where it immediately puts received packets into the buffer queue which |
|||
is serviced by the dispatch threads for optional decryption, dispatch |
|||
decision, optional encryption and delivery. |
|||
|
|||
*-m* _mcast_:: |
|||
|
|||
This tells *rrqnet* to open an ipv4 UDP multicast channel as an |
|||
additional remote channel. |
|||
|
|||
*-t* _tap_:: |
|||
|
|||
This tells *rrqnet* to open the nominated tap (the _tap_ interface |
|||
name) as local channel. |
|||
|
|||
* When a tap is used, stdin and stdout are closed, but stderr remains |
|||
open. |
|||
|
|||
* Without a *-t* argument, *rrqnet* will merely operate as a virtual |
|||
switch among its channels. |
|||
|
|||
* With "*-*" as tap name, *rrqnet* will use stdin/stdout as local |
|||
networking channel in a format compatible with VDE plugs. |
|||
|
|||
_address-block[:port][=cryptfile]_ [ *-i* _mac_[,_mac_]* ]:: |
|||
|
|||
Remotes are declared as +ipv4+ or +ipv6+ network address blocks |
|||
optionally with port and transport encryption key file pathname, and |
|||
optionally with specific MAC addresses (in a comma separated list) to |
|||
ignore. Note that an ipv6 address block might need surrounding square |
|||
brackets, to avoid confusion with the port number. |
|||
|
|||
DETAILED DESCRIPTION |
|||
-------------------- |
|||
|
|||
The intended use of *rrqnet* is to provide VPN (virtual private |
|||
network) connectivity between hosts. Each VPN host runs its own |
|||
*rrqnet* daemon to channel the traffic to/from tap interfaces on the |
|||
hosts via UDP messaging between the hosts. |
|||
|
|||
*rrqnet* is prepared for almost any network layout, even including a |
|||
collection of fully connected hosts, although the more common is a |
|||
"star' formation. See the EXAMPLES section for inspiration. |
|||
|
|||
*rrqnet* includes logic aiming to protect against broadcast cycles. |
|||
Howewer it does not have the more advanced spanning tree logic that is |
|||
offered by bridge interfaces. In general it's best to avoid cycles and |
|||
rather run several *rrqnet* on a host with their local taps connected |
|||
in a bridge interface. |
|||
|
|||
By default *rrqnet* opens an +ipv6+ socket on the given port. This |
|||
mode handles both +ipv6+ and +ipv4+ remotes with +ipv4+ remotes |
|||
handled by means of ipv6-mapped address translations. If *-4* is |
|||
given, *rrqnet* opens an +ipv4+ socket instead, and it cannot then |
|||
have +ipv6+ remotes. |
|||
|
|||
A *rrqnet* daemon delivers the packets received from the local end, |
|||
i.e., the _tap_ or _stdio_, to known remote ends according the |
|||
targeted MAC addresses and established remote channels. Likewise, |
|||
packets from remotes are delivered to the local end or to other |
|||
remotes according to the targeted MAC addresses. If a packet is an |
|||
Ethernet broadcast, it is delivered to all (known) channels except the |
|||
one it came from. |
|||
|
|||
If *rrqnet* is started without *-t* option it will operate like an |
|||
Ethernet switch that provides connectivity among its +UDP+ channels |
|||
without involving the host network other than for the tunneling. |
|||
|
|||
|
|||
REMOTE DECLARTIONS |
|||
~~~~~~~~~~~~~~~~~~ |
|||
|
|||
.ipv4 address block |
|||
|
|||
This format declares remotes by +ipv4+ address, with optional network |
|||
prefix length (0-32), optional port (1-65535) and/or optional key file |
|||
pathname. *updtap* will accept packets from sources that match. If the |
|||
network prefix length, +n+, is omitted or given as 32, and a port is |
|||
given, then the remote is taken as an _uplink_. |
|||
|
|||
.matching ipv4 uplink and downlink |
|||
==== |
|||
---- |
|||
[1.2.3.4]# rrqnet -t vpn0 2300 5.6.7.1:2300=/sec/vpn0.key |
|||
[5.6.7.1]# rrqnet -t vpn0 2300 1.2.3.0/24:2300=/sec/vpn0.key |
|||
---- |
|||
==== |
|||
|
|||
.plain ipv6 address block |
|||
|
|||
This format declares remotes by ipv6 address, with optional network |
|||
prefix length (0-128) and/or optional key file pathname. *updtap* will |
|||
accept packets from sources that match. This format (without square |
|||
brackets) is without port number part, and it thus only declares a |
|||
prefix mask for allowed sender hosts. |
|||
|
|||
.ipv6 address block within square brackets |
|||
|
|||
This format declares remotes by ipv6 address, with optional network |
|||
prefix length (0-128) within square brackets, then optionally a port |
|||
number and/or an optional key file pathname. *updtap* will accept |
|||
packets from sources that match. If the network prefix length, +n+, is |
|||
omitted, or given as 128, and a port number is given, then it declares |
|||
an _uplink_. |
|||
|
|||
.matching ipv6 uplink and downlink |
|||
==== |
|||
---- |
|||
[fd::4]# rrqnet -t vpn0 2300 '[fe::1:4]:2300=/sec/vpn0.key' |
|||
[fe::1:4]# rrqnet -t vpn0 2300 '[fd::/120]:2300=/sec/vpn0.key' |
|||
---- |
|||
==== |
|||
|
|||
Remotes are declarations to match the source IP addresses for UDP |
|||
traffic. It is either a full host and port address, or an address |
|||
block with or without port number. A full network address and port |
|||
(e.g +[fe::1:4]:2300+ of example 2) declares an _uplink_ that the |
|||
declaring *rrqnet* daemon will establish and maintain by means of |
|||
regular heartbeat messaging. An address block declaration defines the |
|||
mask for allowed incoming connections, aka _downlinks_, that teh |
|||
declaring dameon expects are maintained as uplinks by the remote |
|||
*rrqnet* daemons. |
|||
|
|||
The *-i* option, if used for a remote declaration, is followed by a |
|||
comma separated list of the MAC addresses to ignore on the associated |
|||
channel. The *rrqnet* daemon will then just drop any packet with those |
|||
MAC addresses (whether source or destination) on the remotes of the |
|||
channel. |
|||
|
|||
MULTICAST CHANNEL |
|||
----------------- |
|||
|
|||
With the *-m* option, the *rrqnet* daemon also listens for packets on |
|||
the declared ipv4 multicast address. It is then treated as a separate, |
|||
persistent remote channel. |
|||
|
|||
A multicast channel is declared using the format: |
|||
*ipv4:port{=keyfile}*. I.e. it includes the multicast ipv4 address, |
|||
the port number (1-65535), and optionally a key file pathname. The |
|||
multicast channel is an additional communication channel, but anything |
|||
received on it will be treated as being from the multicast IP rather |
|||
than the actual source IP. |
|||
|
|||
.multicast example without other remotes |
|||
==== |
|||
---- |
|||
# rrqnet -m 244.0.2.1:2000 -t vpn0 |
|||
---- |
|||
==== |
|||
|
|||
The multicast channel is compatible with QEMU multicast socket. |
|||
|
|||
TRANSPORT ENCRYPTION |
|||
-------------------- |
|||
|
|||
Transport encryption is added to a channel by menas of using a shared |
|||
key. This is a sizable file, say 1 Mb, of binary data that is used for |
|||
scrambling the network packets. For example, 1 Mb random data is fine. |
|||
|
|||
.preparing 1 Mb key file with random content |
|||
==== |
|||
---- |
|||
dd if=/dev/random of=/sec/keyfile bs=1M count=1 |
|||
---- |
|||
==== |
|||
|
|||
The key file needs to be copied to all hosts. |
|||
|
|||
A channel that has a key file is declared by appending it to the |
|||
channel declaration, as in the following example. |
|||
|
|||
.another example of a downlink with encryption |
|||
==== |
|||
---- |
|||
[10.0.0.1]# rrqnet -v -t tap0 1400 10.2.0.0/16:1400=/sec/keyfile |
|||
---- |
|||
==== |
|||
|
|||
That declaration says that all channels with hosts of ipv4 address |
|||
+10.2.0.0/16+, port 1400, use the file +/sec/keyfile+ for transport |
|||
encryption. |
|||
|
|||
|
|||
FURTHER EXAMPLES |
|||
---------------- |
|||
|
|||
Simple rrqnet set up (ipv6) |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
This is an example set up for connecting two hosts with *rrqnet*, |
|||
without transport encryption. We pretend these hosts are mutually |
|||
reachable with ipv6 addresses +fe::2+ and +fe::1:3+ respectively, and |
|||
we want to use the ipv6 network +fd::1000:0/120+ over *rrqnet*. A |
|||
nominal set up might then be as follows: |
|||
|
|||
.simple rrqnet set up (ipv6) |
|||
==== |
|||
---- |
|||
[fe::2]# ip tuntap add tap0 mode tap |
|||
[fe::2]# ifconfig tap0 fd::1000:10/120 up |
|||
[fe::2]# rrqnet -v -t tap0 1400 '[fe::1:3]:1400' & |
|||
-- |
|||
[fe::1:3]# ip tuntap add tap0 mode tap |
|||
[fe::1:3]# ifconfig tap0 fd::1000:20/120 up |
|||
[fe::1:3]# rrqnet -v -t tap0 1400 '[fe::2]:1400' & |
|||
---- |
|||
==== |
|||
|
|||
Thus, the host +fe::2+ is set up with a tap, +tap0+, having +ipv6+ |
|||
address and net +fd::1000:10/120+, and a *rrqnet* daemon for the tap |
|||
and UDP port +1400+ that uplinks to a remote *rrqnet* at +fe::1:3+ |
|||
port +1400+. Similarly, the host +fe::1:3+ is set up with a tap |
|||
+tap0+, having +ipv6+ address and net +fd::1000:20/120+, and a *rrqnet* |
|||
daemon for the tap and UDP port +1400+ that uplinks to a remote |
|||
*rrqnet* at +fe::2+ port +1400+. |
|||
|
|||
This example also needs ipv6 address resolution set up, which uses the |
|||
MAC addresses of the two taps. Let's say it's +02:00:00:00:00:02+ for |
|||
+tap0+ on +fe::2+ and +04:00:00:00:00:04+ for +tap0+ on +fe::1:3+. |
|||
Then address resolution is established with the following: |
|||
|
|||
.example of ipv6 address resolution set up |
|||
==== |
|||
---- |
|||
[fe::2]# ip neigh add fd::1000:20 dev tap0 lladdr 04:00:00:00:00:04 |
|||
-- |
|||
[fe::1:3]# ip neigh add fd::1000:10 dev tap0 lladdr 02:00:00:00:00:02 |
|||
---- |
|||
==== |
|||
|
|||
Simple rrqnet set up (ipv4) |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
|
|||
This is an example set up for connecting two hosts with *rrqnet*, |
|||
without transport encryption. We pretend these hosts are mutually |
|||
reachable with ipv4 addresses +10.0.0.1+ and +192.168.0.1+ |
|||
respectively, and we want to use the ipv4 network +10.100.100.0/24+ |
|||
over *rrqnet*. A nominal set up might be as follows: |
|||
|
|||
.Simple rrqnet set up (ipv4) |
|||
==== |
|||
---- |
|||
[10.0.0.1]# ip tuntap add tap0 mode tap |
|||
[10.0.0.1]# ifconfig tap0 10.100.100.1/24 up |
|||
[10.0.0.1]# rrqnet -v -t tap0 1400 192.168.0.1:1400 & |
|||
-- |
|||
[192.168.0.1]# ip tuntap add tap0 mode tap |
|||
[192.168.0.1]# ifconfig tap0 10.100.100.2/24 up |
|||
[192.168.0.1]# rrqnet -v -t tap0 1400 10.0.0.1:1400 & |
|||
---- |
|||
==== |
|||
|
|||
Thus, the host +10.0.0.1+ is set up with a tap, +tap0+, having ipv4 |
|||
address and net +10.100.100.1/24+, and a *rrqnet* daemon for the tap |
|||
and UDP port +1400+ that uplinks to a remote *rrqnet* at +192.168.0.1+ |
|||
port +1400+. Similarly, the host +192.168.0.1+ is set up with a tap |
|||
+tap0+, having +ipv4+ address and net +10.100.100.2/24+, and a |
|||
*rrqnet* daemon for the tap and UDP port +1400+ that uplinks to a |
|||
remote *rrqnet* at +10.0.0.1+ port 1400. |
|||
|
|||
The kernel automagically performs ipv4 address resolution to learn the |
|||
MAC addresses associated with the remote ipv4 addresses through the |
|||
taps. |
|||
|
|||
rrqnet set up through NAT |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
|
|||
If one of the hosts, say +192.168.0.1+ is behind a NAT router with |
|||
different IP, say, a dynamic IP on the net +10.2.0.0/16+, we need a |
|||
different set up. In this scenario, the first host would be set up as |
|||
a "server" and the second a client that would utilize the router's NAT |
|||
function for return traffic. The set up would be as follows: |
|||
|
|||
.rrqnet set up through NAT |
|||
==== |
|||
---- |
|||
[10.0.0.1]# ip tuntap add tap0 mode tap |
|||
[10.0.0.1]# ifconfig tap0 10.100.100.1 up |
|||
[10.0.0.1]# rrqnet -v -t tap0 1400 10.2.0.0/16:1400 & |
|||
-- |
|||
[192.168.0.1]# ip tuntap add tap0 mode tap |
|||
[192.168.0.1]# ifconfig tap0 10.100.100.2 up |
|||
[192.168.0.1]# rrqnet -v -t tap0 1400 10.0.0.1:1400 & |
|||
---- |
|||
==== |
|||
|
|||
Thus, the "server" is set up to allow connections from any host on the |
|||
network +10.2.0.0/16+, port 1400, while the "client" is set up the |
|||
same way as in the simple example above. The client will establish and |
|||
uphold the connection by virtue of its 30 second "heart beat", and |
|||
return traffic will be channeled via the router's NAT function. |
|||
|
|||
Note that the server sees the _external_ IP of the client and not its |
|||
_internal_ IP. The server's *rrqnet* therefor has a remote declaration |
|||
to allow messages from that external IP, and in the example case, even |
|||
an address block of a 16 bit common prefix (the choice of a 16 bit |
|||
prefix is merely for the sake of this example). |
|||
|
|||
Multiple client hosts |
|||
~~~~~~~~~~~~~~~~~~~~~ |
|||
|
|||
In a "client-server" set up, there can be any number of "client" |
|||
hosts. However, the "clients" behind a common NAT router must then use |
|||
distinct ports as otherwise the router will be confused about the |
|||
return traffic. |
|||
|
|||
With multiple remote channels, a *rrqnet* daemon serves as a network |
|||
switch that forwards traffic in between the channels as well as to and |
|||
from the "server" tap. The daemon also forwards Ethernet broadcasts |
|||
out on all established channels in support of ARP messaging. |
|||
|
|||
Further, a *rrqnet* daemon may be both a "server" with down-link |
|||
channels, and a "client" with one or more up-link channels, all at the |
|||
same time. Such a daemon forwards traffic between all established |
|||
channels by means of the Ethernet addresses, as well as broadcasts |
|||
onto all channels |
|||
|
|||
Stdio network |
|||
~~~~~~~~~~~~~ |
|||
The *rrqnet* daemon may be set up to use standard input/output rather |
|||
than a tap for local network traffic. This operation mode has some |
|||
rare use cases, such as linking two *rrqnet* daemons, or connecting to |
|||
a VDE network. For example: |
|||
|
|||
.stdio network between two updtap plugs |
|||
==== |
|||
---- |
|||
# dpipe rrqnet 1400 0.0.0.0/0=keyfile0 = rrqnet 1401 0.0.0.0/0=keyfile1 & |
|||
---- |
|||
==== |
|||
|
|||
That example set up would make a connection between the two "server" |
|||
daemons operating at different UDP ports, accepting messages from any |
|||
ipv4 host, where port +1400+ has +keyfile0+ for transport encryption, |
|||
and +1401+ has +keyfile1+ for transport encryption. |
|||
|
|||
Another example would be for connecting the *rrqnet* traffic to a VDE |
|||
network via a +vde_plug+ as in the following example: |
|||
|
|||
.stdio network to a vde_plug |
|||
==== |
|||
---- |
|||
# dpipe rrqnet 1400 0.0.0.0/0 = vde_plug /tmp/vde1.ctl & |
|||
---- |
|||
==== |
|||
|
|||
Note that *rrqnet* and +vde_plug+ use compatible stdio packet |
|||
representation. |
|||
|
|||
NOTES |
|||
----- |
|||
|
|||
The UDP receiver in *rrqnet* accepts packets from the specified remote |
|||
ends only, but it doesn't perform any payload verification. Messages |
|||
smaller than 12 bytes are taken as "heartbeats", and larger messages |
|||
are first decrypted as applicable, then treated as Ethernet messages |
|||
and delivered according to their destination MAC addresses. *rrqnet* |
|||
versions after 0.2.3 adds some data to the Ethernet packet in the UDP |
|||
communication. |
|||
|
|||
*rrqnet* bridges its connections, and forwards Ethernet broadcasts to |
|||
all known end-points except the incoming one. The input logic takes |
|||
care of avoiding broadcast cycles. Still, the safe advice is that one |
|||
should avoid a cyclic *rrqnet* set up except for single-hop cliques of |
|||
host groups. |
|||
|
|||
*rrqnet* does not have any Spanning Tree Logic (STL), but only some |
|||
simple timing logic based on binding MAC addresses to remotes. That |
|||
binding is sticky for a short time: 6s for broadcast and 20s for |
|||
unicast. Any packet received during that time from the same MAC |
|||
address via another remote is dropped. Also, a downlink without |
|||
incoming traffic for 3 minutes is considered stale. |
|||
|
|||
*rrqnet* sends a "heartbeat" of an empty UDP message on its uplinks |
|||
every 30 seconds. This is done in order to maintain the channel with |
|||
the remote end without actually binding any MAC address. |
|||
|
|||
When the local input is a tap, *rrqnet* closes standard input and |
|||
standard output, but not standard error, before entering the packet |
|||
handling loop. |
|||
|
|||
Using +-t -+ for stdin/stdout packet traffic is compatible with |
|||
+vde_plug+. |
|||
|
|||
SEE ALSO |
|||
-------- |
|||
*rrqnet-cron.sh(8)* - Management script to uphold a *rrqnet* plug. |
|||
|
|||
*udptun(8)* - Packet tunneling over UDP. |
|||
|
|||
*vde_plug(1)* - Virtual Distributed Ethernet plug. |
|||
|
|||
AUTHOR |
|||
------ |
|||
Ralph Rönnquist <ralph.ronnquist@gmail.com> |
File diff suppressed because it is too large
@ -0,0 +1,38 @@ |
|||
#!/bin/bash |
|||
# |
|||
# rrqnet helper script for establishing a rule based route table for a |
|||
# given interface with given IP with default route to given gateway IP |
|||
# on the interface link. |
|||
# $1 = interface |
|||
# $2 = interface IP |
|||
# $3 = gateway IP |
|||
# |
|||
# This will retry every second until the setup is successful. Should |
|||
# be spawned in a conf file, eg: |
|||
# /etc/rrqnet/set-source-route.sh $TAP $IP $GW > /dev/null 2>&1 & |
|||
# |
|||
|
|||
TAP=$1 |
|||
IP=$2 |
|||
GW=$3 |
|||
: ${TIX:=200} |
|||
|
|||
function set-source-route() { |
|||
grep -q "$TIX $TAP" /etc/iproute2/rt_tables || \ |
|||
echo "$TIX $TAP" >> /etc/iproute2/rt_tables |
|||
if [ -z "$(ip rule list from ${IP%/*})" ] ; then |
|||
ip rule add from ${IP%/*} lookup $TAP || return 1 |
|||
fi |
|||
if [ -z "$(ip route show table $TAP | grep ^$GW)" ] ; then |
|||
ip route add $GW dev $TAP scope link src ${IP%/*} table $TAP || \ |
|||
return 1 |
|||
fi |
|||
if [ -z "$(ip route show table $TAP | grep default)" ] ; then |
|||
ip route add default via $GW dev $TAP table $TAP || return 1 |
|||
fi |
|||
ip route show table $TAP |
|||
} |
|||
|
|||
set-source-route && exit 0 |
|||
sleep 1 |
|||
exec $0 $* |
@ -0,0 +1,16 @@ |
|||
#ifndef sockaddr_H |
|||
#define sockaddr_H |
|||
|
|||
#include <arpa/inet.h> |
|||
#include <sys/socket.h> |
|||
|
|||
// IP Address union, with flag field
|
|||
struct SockAddr { |
|||
union { |
|||
struct sockaddr in; |
|||
struct sockaddr_in in4; |
|||
struct sockaddr_in6 in6; |
|||
} ; |
|||
}; |
|||
|
|||
#endif |
Loading…
Reference in new issue