mirror of
https://github.com/ivre/masscanned.git
synced 2025-10-02 14:48:22 +00:00
CI: add build workflow
This commit is contained in:
parent
dbd4d57222
commit
12aa60b848
6 changed files with 106 additions and 10 deletions
82
.github/workflows/test.yml
vendored
Normal file
82
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
# This file is part of masscanned.
|
||||||
|
# Copyright 2021 - The IVRE project
|
||||||
|
#
|
||||||
|
# Masscanned 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 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Masscanned 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 Masscanned. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
name: Build masscanned
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Git checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get Rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
|
||||||
|
- name: Run cargo build
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
|
||||||
|
- name: Run cargo test
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
|
||||||
|
- name: Create build archive
|
||||||
|
run: tar cf masscanned.tar target/debug/masscanned
|
||||||
|
|
||||||
|
- name: Upload binary
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: masscanned.tar
|
||||||
|
path: masscanned.tar
|
||||||
|
|
||||||
|
test:
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Git checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get binary
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: masscanned.tar
|
||||||
|
|
||||||
|
- name: Extract build archive
|
||||||
|
run: tar xf masscanned.tar
|
||||||
|
|
||||||
|
- name: Use Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: sudo pip install -r test/requirements.txt
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: sudo python test/test_masscanned.py
|
||||||
|
|
||||||
|
- name: Display logs
|
||||||
|
run: echo STDOUT; cat test/res/masscanned.stdout && echo && echo STDERR && cat test/res/masscanned.stderr
|
||||||
|
if: failure()
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -5,6 +5,8 @@ Cargo.lock
|
||||||
# Vim temporary files
|
# Vim temporary files
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
|
# Emacs temporary files
|
||||||
|
*~
|
||||||
|
|
||||||
*__pycache__*
|
*__pycache__*
|
||||||
test/res/*
|
test/res/*
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
[](https://github.com/ivre/masscanned/actions/workflows/test.yml?branch=master)
|
||||||
|
|
||||||
# Masscanned
|
# Masscanned
|
||||||
|
|
||||||
**Masscanned** (name inspired, of course, by [masscan](https://github.com/robertdavidgraham/masscan))
|
**Masscanned** (name inspired, of course, by [masscan](https://github.com/robertdavidgraham/masscan))
|
||||||
|
|
2
test/requirements.txt
Normal file
2
test/requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
scapy
|
||||||
|
requests
|
|
@ -29,20 +29,22 @@ LOG = logging.getLogger(__name__)
|
||||||
LOG.setLevel(logging.DEBUG)
|
LOG.setLevel(logging.DEBUG)
|
||||||
LOG.addHandler(ch)
|
LOG.addHandler(ch)
|
||||||
|
|
||||||
tests = list()
|
tests = []
|
||||||
|
errors = []
|
||||||
|
|
||||||
# decorator to automatically add a function to tests
|
# decorator to automatically add a function to tests
|
||||||
def test(f):
|
def test(f):
|
||||||
|
global errors, tests
|
||||||
OK = "\033[1mOK\033[0m"
|
OK = "\033[1mOK\033[0m"
|
||||||
KO = "\033[1m\033[1;%dmKO\033[0m" % 31
|
KO = "\033[1m\033[1;%dmKO\033[0m" % 31
|
||||||
global tests
|
|
||||||
fname = f.__name__.ljust(50, '.')
|
fname = f.__name__.ljust(50, '.')
|
||||||
def w(iface):
|
def w(iface):
|
||||||
try:
|
try:
|
||||||
f(iface)
|
f(iface)
|
||||||
LOG.info("{}{}".format(fname, OK))
|
LOG.info("{}{}".format(fname, OK))
|
||||||
except AssertionError as e:
|
except AssertionError as e:
|
||||||
LOG.info("{}{}: {}".format(fname, KO, e))
|
LOG.error("{}{}: {}".format(fname, KO, e))
|
||||||
|
errors.append(fname)
|
||||||
tests.append(w)
|
tests.append(w)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@ def check_ipv6_checksum(pkt):
|
||||||
@test
|
@test
|
||||||
def test_arp_req(iface):
|
def test_arp_req(iface):
|
||||||
##### ARP #####
|
##### ARP #####
|
||||||
arp_req = Ether()/ARP(psrc='192.0.0.2', pdst=IPV4_ADDR)
|
arp_req = Ether(dst=ETHER_BROADCAST)/ARP(psrc='192.0.0.2', pdst=IPV4_ADDR)
|
||||||
arp_repl = iface.sr1(arp_req, timeout=1)
|
arp_repl = iface.sr1(arp_req, timeout=1)
|
||||||
assert(arp_repl is not None), "expecting answer, got nothing"
|
assert(arp_repl is not None), "expecting answer, got nothing"
|
||||||
assert(ARP in arp_repl), "no ARP layer found"
|
assert(ARP in arp_repl), "no ARP layer found"
|
||||||
|
@ -425,7 +427,8 @@ def test_ipv4_udp_stun(iface):
|
||||||
assert(length == 12), "expected length 12, got {}".format(length)
|
assert(length == 12), "expected length 12, got {}".format(length)
|
||||||
assert(magic == 0x2112a442), "expected magic 0x2112a442, got 0x{:08x}".format(magic)
|
assert(magic == 0x2112a442), "expected magic 0x2112a442, got 0x{:08x}".format(magic)
|
||||||
assert(tid == b'\x00' * 12), "expected tid 0x000000000000000000000000, got {:x}".format(tid)
|
assert(tid == b'\x00' * 12), "expected tid 0x000000000000000000000000, got {:x}".format(tid)
|
||||||
assert(data == bytes.fromhex("000100080001") + struct.pack(">H", sport) + bytes.fromhex("00000000")), "unexpected data"
|
assert(data[:8] == bytes.fromhex("000100080001") + struct.pack(">H", sport)), f"unexpected data {data!r}"
|
||||||
|
assert(len(data) == 12), f"unexpected data {data!r}"
|
||||||
|
|
||||||
@test
|
@test
|
||||||
def test_ipv6_udp_stun(iface):
|
def test_ipv6_udp_stun(iface):
|
||||||
|
@ -474,7 +477,8 @@ def test_ipv4_udp_stun_change_port(iface):
|
||||||
assert(type_ == 0x0101), "expected type 0X0101, got 0x{:04x}".format(type_)
|
assert(type_ == 0x0101), "expected type 0X0101, got 0x{:04x}".format(type_)
|
||||||
assert(length == 12), "expected length 12, got {}".format(length)
|
assert(length == 12), "expected length 12, got {}".format(length)
|
||||||
assert(tid == bytes.fromhex("03a3b9464dd8eb75e19481474293845c")), "expected tid 0x03a3b9464dd8eb75e19481474293845c, got %r" % tid
|
assert(tid == bytes.fromhex("03a3b9464dd8eb75e19481474293845c")), "expected tid 0x03a3b9464dd8eb75e19481474293845c, got %r" % tid
|
||||||
assert(data == bytes.fromhex("000100080001") + struct.pack(">H", sport) + bytes.fromhex("00000000")), "unexpected data"
|
assert(data[:8] == bytes.fromhex("000100080001") + struct.pack(">H", sport)), f"unexpected data {data!r}"
|
||||||
|
assert(len(data) == 12), f"unexpected data {data!r}"
|
||||||
|
|
||||||
@test
|
@test
|
||||||
def test_ipv6_udp_stun_change_port(iface):
|
def test_ipv6_udp_stun_change_port(iface):
|
||||||
|
@ -591,3 +595,4 @@ def test_all(iface):
|
||||||
# execute tests
|
# execute tests
|
||||||
for t in tests:
|
for t in tests:
|
||||||
t(iface)
|
t(iface)
|
||||||
|
return len(errors)
|
||||||
|
|
|
@ -42,7 +42,8 @@ LOG = logging.getLogger(__name__)
|
||||||
LOG.setLevel(logging.INFO)
|
LOG.setLevel(logging.INFO)
|
||||||
LOG.addHandler(ch)
|
LOG.addHandler(ch)
|
||||||
|
|
||||||
conf.iface = 'tap0'
|
IFACE = "tap0"
|
||||||
|
|
||||||
conf.verb = 0
|
conf.verb = 0
|
||||||
|
|
||||||
# prepare configuration file for masscanned
|
# prepare configuration file for masscanned
|
||||||
|
@ -52,7 +53,8 @@ with open(ipfile, "w") as f:
|
||||||
f.write("{}\n".format(IPV6_ADDR))
|
f.write("{}\n".format(IPV6_ADDR))
|
||||||
|
|
||||||
# create test interface
|
# create test interface
|
||||||
tap = TunTapInterface(resolve_iface(conf.iface))
|
tap = TunTapInterface(IFACE)
|
||||||
|
conf.iface = resolve_iface(IFACE)
|
||||||
|
|
||||||
# set interface
|
# set interface
|
||||||
subprocess.run("ip a a dev {} 192.0.0.2".format(conf.iface), shell=True)
|
subprocess.run("ip a a dev {} 192.0.0.2".format(conf.iface), shell=True)
|
||||||
|
@ -67,12 +69,13 @@ masscanned = subprocess.Popen("RUST_BACKTRACE=1 ./target/debug/masscanned -vvvvv
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
test_all(tap)
|
result = test_all(tap)
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
pass
|
result = -1
|
||||||
|
|
||||||
# terminate masscanned
|
# terminate masscanned
|
||||||
masscanned.kill()
|
masscanned.kill()
|
||||||
# terminate capture
|
# terminate capture
|
||||||
sleep(2)
|
sleep(2)
|
||||||
tcpdump.kill()
|
tcpdump.kill()
|
||||||
|
sys.exit(result)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue