summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@anytun.org>2016-02-25 00:34:22 +0100
committerChristian Pointner <equinox@anytun.org>2016-02-25 00:34:22 +0100
commit59106bf1a66a4e210f8cc98bddb760cfa8cff06a (patch)
tree998eda912f48de7523aa22e446531c2129feb429
parentupdated doc and other stuff after moving to GIT (diff)
parentfixed checking (missing OpenssL License File) (diff)
merged rail mode to master
-rw-r--r--ChangeLog3
-rw-r--r--doc/uanytun.855
-rw-r--r--doc/uanytun.8.txt50
-rw-r--r--etc/uanytun/rail-client/config91
-rw-r--r--etc/uanytun/rail-server/config91
-rw-r--r--src/options.c8
-rw-r--r--src/options.h1
-rw-r--r--src/uanytun.c11
-rw-r--r--src/udp.c111
-rw-r--r--src/udp.h3
10 files changed, 395 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index 757dedb..2e3458e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
-2016.?.? -- Version 0.?.?
+201?.??.?? -- Version 0.?.?
+* added RAIL mode
* moved to GIT
2014.06.21 -- Version 0.3.5
diff --git a/doc/uanytun.8 b/doc/uanytun.8
index 977f3e9..7881569 100644
--- a/doc/uanytun.8
+++ b/doc/uanytun.8
@@ -42,9 +42,10 @@ uanytun \- micro anycast tunneling daemon
[ \fB\-L|\-\-log\fR <target>:<level>[,<param1>[,<param2>[\&.\&.]]] ]
[ \fB\-U|\-\-debug\fR ]
[ \fB\-i|\-\-interface\fR <ip\-address> ]
- [ \fB\-p|\-\-port\fR <port> ]
+ [ \fB\-p|\-\-port\fR <port>[:<port>] ]
+ [ \fB\-Y|\-\-rail\-mode\fR ]
[ \fB\-r|\-\-remote\-host\fR <hostname|ip> ]
- [ \fB\-o|\-\-remote\-port\fR <port> ]
+ [ \fB\-o|\-\-remote\-port\fR <port>[:<port>] ]
[ \fB\-4|\-\-ipv4\-only\fR ]
[ \fB\-6|\-\-ipv6\-only\fR ]
[ \fB\-d|\-\-dev\fR <name> ]
@@ -148,9 +149,22 @@ to run in debug mode\&. It implicits
This IP address is used as the sender address for outgoing packets\&. The default is to not use a special inteface and just bind on all interfaces\&.
.RE
.PP
-\fB\-p, \-\-port \fR\fB\fI<port>\fR\fR
+\fB\-p, \-\-port \fR\fB\fI<port>[:<port>]\fR\fR
.RS 4
-The local UDP port that is used to send and receive the payload data\&. The two tunnel endpoints can use different ports\&. default: 4444
+The local UDP port that is used to send and receive the payload data\&. The two tunnel endpoints can use different ports\&. The default port is 4444\&. In
+\fBRAIL\fR
+mode you must specify a port range\&. See section
+\fBRAIL\fR
+below to find out what this is\&.
+.RE
+.PP
+\fB\-Y, \-\-rail\-mode\fR
+.RS 4
+This option instructs
+\fBuAnytun\fR
+to run in RAIL mode\&. See section
+\fBRAIL\fR
+below to find out what this is\&.
.RE
.PP
\fB\-r, \-\-remote\-host \fR\fB\fI<hostname|ip>\fR\fR
@@ -158,9 +172,12 @@ The local UDP port that is used to send and receive the payload data\&. The two
This option can be used to specify the remote tunnel endpoint\&. In case of anycast tunnel endpoints, the anycast IP address has to be used\&. If you do not specify an address, it is automatically determined after receiving the first data packet\&.
.RE
.PP
-\fB\-o, \-\-remote\-port \fR\fB\fI<port>\fR\fR
+\fB\-o, \-\-remote\-port \fR\fB\fI<port>[:<port>]\fR\fR
.RS 4
-The UDP port used for payload data by the remote host (specified with \-p on the remote host)\&. If you do not specify a port, it is automatically determined after receiving the first data packet\&.
+The UDP port used for payload data by the remote host (specified with \-p on the remote host)\&. If you do not specify a port, it is automatically determined after receiving the first data packet\&. When RAIL mode is enabled the port range must be of the same length as the range defined with
+\fB\-p, \-\-port\fR\&. See section
+\fBRAIL\fR
+below for more information about this mode\&.
.RE
.PP
\fB\-4, \-\-ipv4\-only\fR
@@ -368,6 +385,9 @@ The number of bytes to use for the auth tag\&. This value defaults to 10 bytes u
\fInull\fR
auth algo is used in which case it defaults to 0\&.
.RE
+.SH "RAIL"
+.sp
+\fBRAIL\fR stands for Redundant Array of Inexpensive Links\&. Like RAID spreads the blocks of a disk volume over multiple physical disks, \fBRAIL\fR will spread the UDP packets over multiple physical links\&. More precisly for each packet \fBuAnytun\fR reads, from the TUN/TAP device, it will send out multiple UDP packets\&. All of those to the same host but with different destination ports\&. Using policy\-based routing mechanisms these packets can now be seperated and sent out on several interfaces\&. The server\-side will then pick the first of the packets that arrive and discards all others\&. For this to work the size of the sequence window (\fB\-w\fR) must not be set to 0\&. As soon as the server\-side learns the remote endpoints of all or some of the links it will as well send multiple UDP packets for each payload packet\&.
.SH "EXAMPLES"
.SS "P2P Setup between two unicast enpoints:"
.sp
@@ -415,6 +435,29 @@ uanytun \-r anycast\&.anytun\&.org \-d anytun0 \-t tun \-n 192\&.0\&.2\&.2/30 \-
.sp
As \fBuAnytun\fR can\(cqt work as an anycast endpoint it can\(cqt be used for this purpose\&. You have to use \fBAnytun\fR for that job\&.
.RE
+.SS "Rail Setup for 3 links:"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBClient:\fR
+.RS 4
+.sp
+uanytun \-t tun \-n 192\&.168\&.42\&.2/30 \-c aes\-ctr\-256 \-k aes\-ctr\-256 \-E rail_MODE_is_VERY_cool \-e client \-w 64 \-Y \-p 1233:1235 \-r rail\&.example\&.com \-o 4440:4442
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBServer:\fR
+.RS 4
+.sp
+uanytun \-t tun \-n 192\&.168\&.42\&.1/30 \-c aes\-ctr\-256 \-k aes\-ctr\-256 \-E rail_MODE_is_VERY_cool \-e server \-w 64 \-Y \-p 4440:4442
+.RE
.SH "BUGS"
.sp
Most likely there are some bugs in \fBuAnytun\fR\&. If you find a bug, please let the developers know at uanytun@anytun\&.org\&. Of course, patches are preferred\&.
diff --git a/doc/uanytun.8.txt b/doc/uanytun.8.txt
index ed978d4..5a507ca 100644
--- a/doc/uanytun.8.txt
+++ b/doc/uanytun.8.txt
@@ -21,9 +21,10 @@ uanytun
[ -L|--log <target>:<level>[,<param1>[,<param2>[..]]] ]
[ -U|--debug ]
[ -i|--interface <ip-address> ]
- [ -p|--port <port> ]
+ [ -p|--port <port>[:<port>] ]
+ [ -Y|--rail-mode ]
[ -r|--remote-host <hostname|ip> ]
- [ -o|--remote-port <port> ]
+ [ -o|--remote-port <port>[:<port>] ]
[ -4|--ipv4-only ]
[ -6|--ipv6-only ]
[ -d|--dev <name> ]
@@ -110,10 +111,16 @@ passed to the daemon:
packets. The default is to not use a special inteface and just
bind on all interfaces.
-*-p, --port '<port>'*::
+*-p, --port '<port>[:<port>]'*::
The local UDP port that is used to send and receive the
payload data. The two tunnel endpoints can use different
- ports. default: 4444
+ ports. The default port is 4444.
+ In *RAIL* mode you must specify a port range. See section
+ *RAIL* below to find out what this is.
+
+*-Y, --rail-mode*::
+ This option instructs *uAnytun* to run in RAIL mode. See section
+ *RAIL* below to find out what this is.
*-r, --remote-host '<hostname|ip>'*::
This option can be used to specify the remote tunnel
@@ -122,11 +129,14 @@ passed to the daemon:
an address, it is automatically determined after receiving
the first data packet.
-*-o, --remote-port '<port>'*::
+*-o, --remote-port '<port>[:<port>]'*::
The UDP port used for payload data by the remote host
(specified with -p on the remote host). If you do not specify
a port, it is automatically determined after receiving
the first data packet.
+ When RAIL mode is enabled the port range must be of the same length
+ as the range defined with *-p, --port*.
+ See section *RAIL* below for more information about this mode.
*-4, --ipv4-only*::
Resolv to IPv4 addresses only. The default is to resolv both
@@ -248,6 +258,21 @@ passed to the daemon:
unless the 'null' auth algo is used in which case it defaults to 0.
+RAIL
+----
+
+*RAIL* stands for Redundant Array of Inexpensive Links. Like RAID spreads
+the blocks of a disk volume over multiple physical disks, *RAIL* will spread the
+UDP packets over multiple physical links. More precisly for each packet *uAnytun*
+reads, from the TUN/TAP device, it will send out multiple UDP packets. All of those to
+the same host but with different destination ports. Using policy-based routing mechanisms
+these packets can now be seperated and sent out on several interfaces.
+The server-side will then pick the first of the packets that arrive and discards all others.
+For this to work the size of the sequence window (*-w*) must not be set to 0.
+As soon as the server-side learns the remote endpoints of all or some of the links it will
+as well send multiple UDP packets for each payload packet.
+
+
EXAMPLES
--------
@@ -280,6 +305,21 @@ As *uAnytun* can't work as an anycast endpoint it can't be used for this purpose
have to use *Anytun* for that job.
+Rail Setup for 3 links:
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Client:
+^^^^^^^
+
+uanytun -t tun -n 192.168.42.2/30 -c aes-ctr-256 -k aes-ctr-256 -E rail_MODE_is_VERY_cool
+ -e client -w 64 -Y -p 1233:1235 -r rail.example.com -o 4440:4442
+
+Server:
+^^^^^^^
+uanytun -t tun -n 192.168.42.1/30 -c aes-ctr-256 -k aes-ctr-256 -E rail_MODE_is_VERY_cool
+ -e server -w 64 -Y -p 4440:4442
+
+
BUGS
----
diff --git a/etc/uanytun/rail-client/config b/etc/uanytun/rail-client/config
new file mode 100644
index 0000000..3671eee
--- /dev/null
+++ b/etc/uanytun/rail-client/config
@@ -0,0 +1,91 @@
+#############################
+## Main options #
+#############################
+
+role client
+
+## device type tun = ip/ipv6, tap = ethernet
+type tun
+
+## Automaticaly configure the interface
+## the address hast to be supplied in CIDR notation
+ifconfig 192.168.42.2/30
+
+## payload encryption algorithm
+#cipher null
+#cipher aes-ctr-128
+#cipher aes-ctr-192
+#cipher aes-ctr-256
+cipher aes-ctr
+
+## message authentication algorithm
+#auth-algo null
+auth-algo sha1
+
+##message auth tag length
+#auth-tag-length 10
+
+## Passphrase
+## this is used to generate the crypto-key and salt
+## this should be al least 30 characters
+passphrase RAID_is_nice_but_RAIL_is_cooler
+
+## local ip address to bind to (for tunnel data)
+## (if you run an anycast cluster this has to be the anycast ip address)
+#interface <ip-address>
+
+## local port to bind to (for tunnel data)
+## the number of ports here must be at least as high as the number of
+## remote ports - so in this case up to 5 links may be used
+port 8880:8884
+
+## The remote host and port (for RAIL a port range is needed)
+remote-host rail.example.com
+remote-port 8880:8884
+
+## enable RAIL mode
+rail-mode
+
+#############################
+## Debug options #
+#############################
+
+## don't run in background
+#nodaemonize
+
+## additional log to standard output with a level of 5
+#log stdout:5
+
+
+#############################
+## Expert options #
+#############################
+
+## log to syslog with a level of 3
+log syslog:3,uanytun-rail-client,daemon
+
+## change user and group after init
+#username uanytun
+#groupname uanytun
+
+## chroot to users home directory
+#chroot /var/run/uanytun
+
+## key derivation pseudo random function
+#kd-prf null
+#kd-prf aes-ctr
+#kd-prf aes-ctr-128
+#kd-prf aes-ctr-192
+#kd-prf aes-ctr-256
+
+## Device name
+dev rail0
+
+## Manually set encryption key and salt
+## (this replaces the passphrase)
+#key 0123456789ABCDEF0123456789ABCDEF
+#salt 0123456789ABCD0123456789ABCD
+
+## Setting a window size > 0 will enable replay protection
+## This is needed for RAIL to work
+window-size 100
diff --git a/etc/uanytun/rail-server/config b/etc/uanytun/rail-server/config
new file mode 100644
index 0000000..0f34557
--- /dev/null
+++ b/etc/uanytun/rail-server/config
@@ -0,0 +1,91 @@
+#############################
+## Main options #
+#############################
+
+role server
+
+## device type tun = ip/ipv6, tap = ethernet
+type tun
+
+## Automaticaly configure the interface
+## the address hast to be supplied in CIDR notation
+ifconfig 192.168.42.1/30
+
+## payload encryption algorithm
+#cipher null
+#cipher aes-ctr-128
+#cipher aes-ctr-192
+#cipher aes-ctr-256
+cipher aes-ctr
+
+## message authentication algorithm
+#auth-algo null
+auth-algo sha1
+
+##message auth tag length
+#auth-tag-length 10
+
+## Passphrase
+## this is used to generate the crypto-key and salt
+## this should be al least 30 characters
+passphrase RAID_is_nice_but_RAIL_is_cooler
+
+## local ip address to bind to (for tunnel data)
+## (if you run an anycast cluster this has to be the anycast ip address)
+#interface <ip-address>
+
+## local port to bind to (for tunnel data)
+## the number of ports here must be at least as high as the number of
+## remote ports defined at the client configuration (in this case 5)
+port 8880:8884
+
+## The remote host and port will be learned from the first messages
+#remote-host client.unknown
+#remote-port 8880:8884
+
+## enable RAIL mode
+rail-mode
+
+#############################
+## Debug options #
+#############################
+
+## don't run in background
+#nodaemonize
+
+## additional log to standard output with a level of 5
+#log stdout:5
+
+
+#############################
+## Expert options #
+#############################
+
+## log to syslog with a level of 3
+log syslog:3,uanytun-rail-server,daemon
+
+## change user and group after init
+#username uanytun
+#groupname uanytun
+
+## chroot to users home directory
+#chroot /var/run/uanytun
+
+## key derivation pseudo random function
+#kd-prf null
+#kd-prf aes-ctr
+#kd-prf aes-ctr-128
+#kd-prf aes-ctr-192
+#kd-prf aes-ctr-256
+
+## Device name
+dev rail0
+
+## Manually set encryption key and salt
+## (this replaces the passphrase)
+#key 0123456789ABCDEF0123456789ABCDEF
+#salt 0123456789ABCD0123456789ABCD
+
+## Setting a window size > 0 will enable replay protection
+## This is needed for RAIL to work
+window-size 100
diff --git a/src/options.c b/src/options.c
index c3038bb..015a9a5 100644
--- a/src/options.c
+++ b/src/options.c
@@ -260,6 +260,7 @@ int options_parse(options_t* opt, int argc, char* argv[])
PARSE_INT_PARAM("-s","--sender-id", opt->sender_id_)
PARSE_STRING_LIST("-L","--log", opt->log_targets_)
PARSE_BOOL_PARAM("-U", "--debug", opt->debug_)
+ PARSE_BOOL_PARAM("-Y", "--rail-mode", opt->rail_mode_)
PARSE_STRING_PARAM("-r","--remote-host", opt->remote_addr_)
PARSE_STRING_PARAM("-o","--remote-port", opt->remote_port_)
PARSE_BOOL_PARAM("-4","--ipv4-only", ipv4_only)
@@ -361,6 +362,7 @@ void options_default(options_t* opt)
opt->local_addr_ = NULL;
opt->local_port_ = strdup("4444");
opt->sender_id_ = 0;
+ opt->rail_mode_ = 0;
opt->remote_addr_ = NULL;
opt->remote_port_ = strdup("4444");
opt->resolv_addr_type_ = ANY;
@@ -447,14 +449,15 @@ void options_print_usage()
printf(" [-C|--chroot] <path> chroot to this directory\n");
printf(" [-P|--write-pid] <path> write pid to this file\n");
printf(" [-i|--interface] <ip-address> local ip address to bind to\n");
- printf(" [-p|--port] <port> local port to bind to\n");
+ printf(" [-p|--port] <port>[:<port>] local port to bind to (use port:port for range - RAIL)\n");
printf(" [-s|--sender-id ] <sender id> the sender id to use\n");
printf(" [-L|--log] <target>:<level>[,<param1>[,<param2>..]]\n");
printf(" add a log target, can be invoked several times\n");
printf(" [-U|--debug] don't daemonize and log to stdout with maximum log level\n");
+ printf(" [-Y|--rail-mode] enable RAIL mode\n");
printf(" [-r|--remote-host] <hostname|ip> remote host\n");
- printf(" [-o|--remote-port] <port> remote port\n");
+ printf(" [-o|--remote-port] <port>[:<port>] remote port (use port:port for range - RAIL)\n");
printf(" [-4|--ipv4-only] always resolv IPv4 addresses\n");
printf(" [-6|--ipv6-only] always resolv IPv6 addresses\n");
printf(" [-d|--dev] <name> device name\n");
@@ -507,6 +510,7 @@ void options_print(options_t* opt)
printf("local_addr: '%s'\n", opt->local_addr_);
printf("local_port: '%s'\n", opt->local_port_);
printf("sender_id: %d\n", opt->sender_id_);
+ printf("rail-mode: %s\n", !opt->rail_mode_ ? "false" : "true");
printf("remote_addr: '%s'\n", opt->remote_addr_);
printf("remote_port: '%s'\n", opt->remote_port_);
printf("resolv_addr_type: ");
diff --git a/src/options.h b/src/options.h
index 8f3593f..fa4d554 100644
--- a/src/options.h
+++ b/src/options.h
@@ -75,6 +75,7 @@ struct options_struct {
char* local_addr_;
char* local_port_;
sender_id_t sender_id_;
+ int rail_mode_;
char* remote_addr_;
char* remote_port_;
resolv_addr_type_t resolv_addr_type_;
diff --git a/src/uanytun.c b/src/uanytun.c
index da90eda..c5d6291 100644
--- a/src/uanytun.c
+++ b/src/uanytun.c
@@ -188,16 +188,21 @@ int process_sock_data(tun_device_t* dev, int fd, udp_t* sock, options_t* opt, pl
}
#endif
+ if(sock->rail_mode_)
+ udp_update_remote(sock, fd, &remote);
+
int result = seq_win_check_and_add(seq_win, encrypted_packet_get_sender_id(encrypted_packet), encrypted_packet_get_seq_nr(encrypted_packet));
if(result > 0) {
- log_printf(WARNING, "detected replay attack, discarding packet");
+ if(!(sock->rail_mode_))
+ log_printf(WARNING, "detected replay attack, discarding packet");
return 0;
} else if(result < 0) {
log_printf(ERROR, "memory error at sequence window");
return -2;
}
- udp_update_remote(sock, fd, &remote);
+ if(!sock->rail_mode_)
+ udp_update_remote(sock, fd, &remote);
if(encrypted_packet_get_payload_length(encrypted_packet) <= plain_packet_get_header_length()) {
log_printf(WARNING, "ignoring packet with zero length payload");
@@ -390,7 +395,7 @@ int main(int argc, char* argv[])
udp_t sock;
- ret = udp_init(&sock, opt.local_addr_, opt.local_port_, opt.resolv_addr_type_);
+ ret = udp_init(&sock, opt.local_addr_, opt.local_port_, opt.resolv_addr_type_, opt.rail_mode_);
if(ret) {
log_printf(ERROR, "error on udp_init, exitting");
tun_close(&dev);
diff --git a/src/udp.c b/src/udp.c
index 239e074..568f738 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -161,18 +161,53 @@ static int udp_resolv_local(udp_t* sock, const char* local_addr, const char* por
return 0;
}
-int udp_init(udp_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type)
+static int udp_split_port_range(const char* port, const char* colon, u_int32_t* low, u_int32_t* high)
+{
+ *low = atoi(port);
+ *high = atoi(colon+1);
+ if(*low < 1 || *low > 65535 || *high < 1 || *high > 65535 || *high < *low) {
+ log_printf(ERROR, "illegal port range");
+ return -1;
+ }
+ return 0;
+}
+
+int udp_init(udp_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type, int rail_mode)
{
if(!sock || !port)
return -1;
sock->socks_ = NULL;
sock->active_sock_ = NULL;
+ sock->rail_mode_ = rail_mode;
unsigned int idx = 0;
- int ret = udp_resolv_local(sock, local_addr, port, resolv_type, &idx);
- if(ret)
- return ret;
+ const char* colon = strchr(port, ':');
+ if(!colon) {
+ int ret = udp_resolv_local(sock, local_addr, port, resolv_type, &idx);
+ if(ret)
+ return ret;
+ } else {
+ if(!rail_mode)
+ log_printf(WARNING, "A port range has been defined - enabling RAIL mode");
+ sock->rail_mode_ = 1;
+
+ u_int32_t port_num, port_end;
+ if(udp_split_port_range(port, colon, &port_num, &port_end))
+ return -1;
+ do {
+ char port_str[10];
+ snprintf(port_str, sizeof(port_str), "%d", port_num);
+ int ret = udp_resolv_local(sock, local_addr, port_str, resolv_type, &idx);
+ if(ret)
+ return ret;
+
+ port_num++;
+ } while(port_num <= port_end);
+ }
+
+ if(sock->rail_mode_)
+ log_printf(NOTICE, "RAIL mode enabled");
return 0;
}
@@ -193,7 +228,7 @@ int udp_fill_fd_set(udp_t* sock, fd_set* set)
int udp_has_remote(udp_t* sock)
{
- if(!sock->active_sock_ || !sock->active_sock_->remote_end_set_)
+ if(!sock->rail_mode_ && (!sock->active_sock_ || !sock->active_sock_->remote_end_set_))
return 0;
udp_socket_t* s = sock->socks_;
@@ -206,13 +241,10 @@ int udp_has_remote(udp_t* sock)
return 0;
}
-int udp_resolv_remote(udp_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type)
+static int udp_resolv_remote__(udp_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type)
{
struct addrinfo hints, *res;
- if(!sock || !remote_addr || !port)
- return -1;
-
res = NULL;
memset (&hints, 0, sizeof (hints));
hints.ai_socktype = SOCK_DGRAM;
@@ -268,6 +300,36 @@ int udp_resolv_remote(udp_t* sock, const char* remote_addr, const char* port, re
return 0;
}
+int udp_resolv_remote(udp_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type)
+{
+ if(!sock || !remote_addr || !port)
+ return -1;
+
+ const char* colon = strchr(port, ':');
+ if(!colon) {
+ return udp_resolv_remote__(sock, remote_addr, port, resolv_type);
+ } else {
+ if(!sock->rail_mode_)
+ log_printf(WARNING, "A port range has been defined - enabling RAIL mode");
+ sock->rail_mode_ = 1;
+
+ u_int32_t port_num, port_end;
+ if(udp_split_port_range(port, colon, &port_num, &port_end))
+ return -1;
+ do {
+ char port_str[10];
+ snprintf(port_str, sizeof(port_str), "%d", port_num);
+ int ret = udp_resolv_remote__(sock, remote_addr, port_str, resolv_type);
+ if(ret)
+ return ret;
+
+ port_num++;
+ } while(port_num <= port_end);
+ }
+
+ return 0;
+}
+
void udp_update_remote(udp_t* sock, int fd, udp_endpoint_t* remote)
{
if(!sock)
@@ -351,10 +413,37 @@ int udp_read(udp_t* sock, int fd, u_int8_t* buf, u_int32_t len, udp_endpoint_t*
}
-int udp_write(udp_t* sock, u_int8_t* buf, u_int32_t len)
+static int udp_write_active_sock(udp_t* sock, u_int8_t* buf, u_int32_t len)
{
- if(!sock || !buf || !sock->active_sock_ || !sock->active_sock_->remote_end_set_)
+ if(!sock->active_sock_ || !sock->active_sock_->remote_end_set_)
return 0;
return sendto(sock->active_sock_->fd_, buf, len, 0, (struct sockaddr *)&(sock->active_sock_->remote_end_.addr_), sock->active_sock_->remote_end_.len_);
}
+
+static int udp_write_rail(udp_t* sock, u_int8_t* buf, u_int32_t len)
+{
+ int i=0;
+
+ udp_socket_t* s = sock->socks_;
+ while(s) {
+ if(s->remote_end_set_) {
+ sendto(s->fd_, buf, len, 0, (struct sockaddr *)&(s->remote_end_.addr_), s->remote_end_.len_);
+ i++;
+ }
+ s = s->next_;
+ }
+
+ return len;
+}
+
+int udp_write(udp_t* sock, u_int8_t* buf, u_int32_t len)
+{
+ if(!sock || !buf)
+ return 0;
+
+ if(sock->rail_mode_)
+ return udp_write_rail(sock, buf, len);
+
+ return udp_write_active_sock(sock, buf, len);
+}
diff --git a/src/udp.h b/src/udp.h
index d0d218d..bb266b0 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -72,10 +72,11 @@ typedef struct udp_socket_struct udp_socket_t;
struct udp_struct {
udp_socket_t* socks_;
udp_socket_t* active_sock_;
+ int rail_mode_;
};
typedef struct udp_struct udp_t;
-int udp_init(udp_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type);
+int udp_init(udp_t* sock, const char* local_addr, const char* port, resolv_addr_type_t resolv_type, int rail_mode);
int udp_fill_fd_set(udp_t* sock, fd_set* set);
int udp_has_remote(udp_t* sock);
int udp_resolv_remote(udp_t* sock, const char* remote_addr, const char* port, resolv_addr_type_t resolv_type);