Skip to content

Commit

Permalink
Add smoke tests
Browse files Browse the repository at this point in the history
  • Loading branch information
darkk committed Apr 12, 2016
1 parent f94a981 commit aa6c750
Show file tree
Hide file tree
Showing 23 changed files with 732 additions and 1 deletion.
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ override CFLAGS += -std=c99 -D_XOPEN_SOURCE=600 -D_DEFAULT_SOURCE -D_GNU_SOURCE

all: $(OUT)

.PHONY: all clean distclean
.PHONY: all clean distclean test

tags: *.c *.h
ctags -R
Expand Down Expand Up @@ -97,3 +97,10 @@ clean:
distclean: clean
$(RM) tags $(DEPS)
$(RM) -r gen

tests/__build-tstamp__: $(OUT) tests/[a-z]* tests/[a-z]*/*
cd tests && ./build
touch $@

test: tests/__build-tstamp__
cd tests && env $(TEST_ENV) ./run
10 changes: 10 additions & 0 deletions tests/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash -ex

(cd .. && make)
cp -a ../redsocks ./regw/redsocks

for img in *; do
if [ -d "$img" -a -f "$img/Dockerfile" ]; then
sudo docker build -t redsocks/"$img" ./"$img"/
fi
done
5 changes: 5 additions & 0 deletions tests/cleanup
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash -x
docker ps
vms=$(echo gw web inetd regw dante-{0..1} squid-{8..9} tank{10..14})
docker stop --time 1 $vms
docker rm $vms
200 changes: 200 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
from functools import partial
from multiprocessing.dummy import Pool as ThrPool
from subprocess import check_call, check_output
import os
import time

import pytest

# 10.0.1.0/24 (br-web) -- web, squid, inetd, gw
# 10.0.2.0/24 (br-tank) -- tank, openwrt
# 10.0.8.0/24 (br-txrx) -- gw, openwrt

BR = {
'10.0.1': 'web',
'10.0.8': 'txrx',
'10.0.2': 'tank',
}

GW = {
'web': '10.0.1.1',
'txrx': '10.0.8.1',
'tank': '10.0.2.123',
}

SLEEPING_BEAST = 'sleep 3600'

class VM(object):
def __init__(self, name, tag, ip4=None, cmd='', docker_opt=''):
self.docker = os.environ.get('DOCKER_CMD', '/usr/bin/docker')
self.pipework = os.environ.get('PIPEWORK_CMD', '/usr/bin/pipework')
self.netns = '/var/run/netns'
self.dns = '8.8.8.8'

self.name, self.tag = name, tag
self.cmd, self.docker_opt = cmd, docker_opt
if ip4:
self.ip4 = ip4
self.sha = self.output('sudo docker run --detach --dns {dns} --name {name} --hostname {name} {docker_opt} {tag} {cmd}')
self.pid = int(self.output('docker inspect -f {{{{.State.Pid}}}} {sha}'))
if not os.path.exists(self.netns):
self.call('sudo mkdir {netns}')
self.call('sudo ln -sf /proc/{pid}/ns/net {netns}/{name}')
self.net()
while cmd != SLEEPING_BEAST and 'LISTEN' not in self.do('netstat -ltn'):
time.sleep(0.1)

def net(self):
self.net_noext()
self.net_br()

def net_br(self):
self.net_br_gw()

def net_noext(self):
self.call('sudo ip netns exec {name} ip link set dev eth0 down')
self.call('sudo ip netns exec {name} ip route replace unreachable {dns}/32')

def net_br_gw(self):
self.call('sudo {pipework} br-{br} -i {intif} -l {vethif} {name} {ip4}/24@{gw4}')

def net_br_nogw(self):
self.call('sudo {pipework} br-{br} -i {intif} -l {vethif} {name} {ip4}/24')

@property
def br(self):
return BR[self.ip4.rsplit('.', 1)[0]]
@property
def gw4(self):
return GW[self.br]
@property
def intif(self):
return {'web': 'ethw', 'tank': 'etht', 'txrx': 'ethx'}[self.br]
@property
def vethif(self):
return ('v' + self.intif + self.name)[:15] # IFNAMSIZ 16

def close(self):
if hasattr(self, 'sha'):
self.call('sudo docker stop --time 1 {sha}')
if not getattr(self, 'preserve_root', False):
self.call('sudo docker rm {sha}')
del self.sha
def fmt(self, cmd):
ctx = self.__dict__.copy()
for i in xrange(len(dir(self))):
try:
ret = cmd.format(**ctx).split()
break
except KeyError, e:
key = e.args[0]
ctx[key] = getattr(self, key)
return ret
def output(self, cmd):
return check_output(self.fmt(cmd))
def call(self, cmd):
check_call(self.fmt(cmd))
def do(self, cmd):
return self.output('sudo docker exec {sha} ' + cmd)

class WebVM(VM):
def __init__(self):
VM.__init__(self, 'web', 'redsocks/web', '10.0.1.80')

class InetdVM(VM):
def __init__(self):
VM.__init__(self, 'inetd', 'redsocks/inetd', '10.0.1.13')

class SquidVM(VM):
def __init__(self, no):
VM.__init__(self, 'squid-%d' % no, 'redsocks/squid', '10.0.1.%d' % no,
docker_opt='--ulimit nofile=65535:65535',
cmd='/etc/squid3/squid-%d.conf' % no)
def net(self):
self.net_br_nogw()
self.call('sudo ip netns exec {name} ip route replace 10.0.0.0/16 via 10.0.1.1')

class DanteVM(VM):
def __init__(self, no):
VM.__init__(self, 'dante-%d' % no, 'redsocks/dante', '10.0.1.%d' % (180 + no),
cmd='/etc/danted-%d.conf' % (1080 + no))
def net(self):
self.net_br_nogw()
self.call('sudo ip netns exec {name} ip route replace 10.0.0.0/16 via 10.0.1.1')


class GwVM(VM):
def __init__(self):
VM.__init__(self, 'gw', 'ubuntu:14.04', cmd=SLEEPING_BEAST)
def net_br(self):
self.ip4 = '10.0.1.1'
self.net_br_nogw()
self.ip4 = '10.0.8.1'
self.net_br_nogw()
del self.ip4
self.call('sudo ip netns exec {name} ip route replace unreachable 10.0.2.0/24')

class TankVM(VM):
def __init__(self, no):
assert 1 <= no <= 100
VM.__init__(self, 'tank%d' % no, 'redsocks/tank', '10.0.2.%d' % no, cmd=SLEEPING_BEAST)

class RegwVM(VM):
def __init__(self):
if int(os.environ.get('VALGRIND_TEST', '0')):
self.preserve_root = True
kw = {'cmd': 'valgrind --leak-check=full --show-leak-kinds=all /usr/local/sbin/redsocks -c /usr/local/etc/redsocks.conf'}
else:
kw = {}
VM.__init__(self, 'regw', 'redsocks/regw', **kw)
def net_br(self):
self.ip4 = '10.0.2.123'
self.net_br_nogw()
self.ip4 = '10.0.8.123'
self.net_br_gw()
del self.ip4
for t in TANKS.values():
self.call('sudo ip netns exec {name} iptables -t nat -A PREROUTING --source 10.0.2.%d/32 --dest 10.0.1.0/24 -p tcp -j REDIRECT --to-port %d' % (t, 12340 + t - TANKS_BASE))

def pmap(l):
#return map(lambda x: x(), l)
p = ThrPool(len(l))
try:
return p.map(lambda x: x(), l, chunksize=1)
finally:
p.close()
p.join()

TANKS_BASE = 10
TANKS = {
'connect_none': TANKS_BASE + 0,
'connect_basic': TANKS_BASE + 1,
'connect_digest': TANKS_BASE + 2,
'socks5_none': TANKS_BASE + 3,
'socks5_auth': TANKS_BASE + 4,
}

class _Network(object):
def __init__(self):
check_output('sudo docker ps'.split())
vm = [
GwVM,
WebVM,
InetdVM,
RegwVM,
partial(SquidVM, 8),
partial(SquidVM, 9),
partial(DanteVM, 0),
partial(DanteVM, 1),
]
for t in TANKS.values():
vm.append(partial(TankVM, t))
self.vm = {_.name: _ for _ in pmap(vm)} # pmap saves ~5 seconds
def close(self):
pmap([_.close for _ in self.vm.values()]) # pmap saves ~7 seconds

@pytest.fixture(scope="session")
def net(request):
n = _Network()
request.addfinalizer(n.close)
return n
17 changes: 17 additions & 0 deletions tests/dante/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM ubuntu:14.04

RUN set -o xtrace \
&& sed -i 's,^deb-src,# no src # &,; s,http://archive.ubuntu.com/ubuntu/,mirror://mirrors.ubuntu.com/mirrors.txt,' /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y dante-server

RUN useradd sockusr --user-group \
--home-dir /nonexistent --no-create-home \
--shell /usr/sbin/nologin \
--password '$6$U1HPxoVq$XFqhRetreV3068UCwQA//fGVFUfwfyqeiYpCpeUFAhuMi/wjOhJSzUxb4wUqt9vRnWjO0CDPMkE40ptHWrrIz.'

COPY danted-*.conf /etc/
COPY danted-waitif /usr/sbin/

ENTRYPOINT ["/usr/sbin/danted-waitif", "-d", "-f"]
CMD ["/etc/danted-1080.conf"]
33 changes: 33 additions & 0 deletions tests/dante/danted-1080.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
logoutput: stderr
internal: 0.0.0.0 port = 1080
external: ethw
method: none
clientmethod: none

#extension: bind

# TCP addr rules

client pass {
from: 10.0.8.123/32 port 1-65535 to: 0.0.0.0/0
log: connect error
}
client block {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: connect error
}

# Socks protocol rules

block {
from: 0.0.0.0/0 to: 127.0.0.0/8
log: connect error
}
pass {
from: 10.0.8.123/32 to: 0.0.0.0/0
log: connect error
}
block {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: connect error
}
33 changes: 33 additions & 0 deletions tests/dante/danted-1081.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
logoutput: stderr
internal: 0.0.0.0 port = 1081
external: ethw
method: username
clientmethod: none

#extension: bind

# TCP addr rules

client pass {
from: 10.0.8.123/32 port 1-65535 to: 0.0.0.0/0
log: connect error
}
client block {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: connect error
}

# Socks protocol rules

block {
from: 0.0.0.0/0 to: 127.0.0.0/8
log: connect error
}
pass {
from: 10.0.8.123/32 to: 0.0.0.0/0
log: connect error
}
block {
from: 0.0.0.0/0 to: 0.0.0.0/0
log: connect error
}
5 changes: 5 additions & 0 deletions tests/dante/danted-waitif
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh -x
while ! ip link show ethw up 2>/dev/null | grep -q UP; do
sleep 0.1
done
exec /usr/sbin/danted "$@"
13 changes: 13 additions & 0 deletions tests/inetd/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM ubuntu:14.04

RUN set -o xtrace \
&& sed -i 's,^deb-src,# no src # &,; s,http://archive.ubuntu.com/ubuntu/,mirror://mirrors.ubuntu.com/mirrors.txt,' /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y xinetd

RUN set -o xtrace \
&& apt-get install -y iperf

COPY testing /etc/xinetd.d/testing

CMD ["/usr/sbin/xinetd", "-dontfork", "-pidfile", "/run/xinetd.pid", "-inetd_ipv6"]
47 changes: 47 additions & 0 deletions tests/inetd/testing
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
service daytime
{
disable = no
type = INTERNAL
id = daytime-stream
socket_type = stream
protocol = tcp
user = root
wait = no
flags = IPv6
}

service discard
{
disable = no
type = INTERNAL
id = discard-stream
socket_type = stream
protocol = tcp
user = root
wait = no
flags = IPv6
}

service echo
{
disable = no
type = INTERNAL
id = echo-stream
socket_type = stream
protocol = tcp
user = root
wait = no
flags = IPv6
}

service chargen
{
disable = no
type = INTERNAL
id = chargen-stream
socket_type = stream
protocol = tcp
user = root
wait = no
flags = IPv6
}
Loading

0 comments on commit aa6c750

Please sign in to comment.