mirror of
https://github.com/rtbrick/bngblaster.git
synced 2024-05-06 15:54:57 +00:00
Merge pull request #35 from Istvan91/remove_getuid
Remove mandatory root requirement + some smaller fixes
This commit is contained in:
+2
-2
@@ -39,8 +39,8 @@ set(CURSES_NEED_NCURSES TRUE)
|
||||
include(FindCurses)
|
||||
target_link_libraries(bngblaster ${CURSES_LIBRARIES} crypto jansson ${libdict} m)
|
||||
|
||||
SET(PLATFORM_SPECIFIC_LIBS "-lpthread")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||
set(PLATFORM_SPECIFIC_LIBS "-lpthread")
|
||||
string(APPEND CMAKE_C_FLAGS "-pthread")
|
||||
|
||||
|
||||
# add experimental netmap support
|
||||
|
||||
+55
-21
@@ -3,27 +3,29 @@
|
||||
## Install Ubuntu
|
||||
|
||||
Install dependencies:
|
||||
```
|
||||
|
||||
```cli
|
||||
sudo apt install -y libssl1.1 libncurses5 libjansson4
|
||||
```
|
||||
|
||||
Download and install debian package:
|
||||
https://github.com/rtbrick/bngblaster/releases
|
||||
[https://github.com/rtbrick/bngblaster/releases](https://github.com/rtbrick/bngblaster/releases)
|
||||
|
||||
```
|
||||
```cli
|
||||
sudo dpkg -i <package>
|
||||
```
|
||||
|
||||
This command installs the BNG Blaster to `/usr/sbin/bngblaster`.
|
||||
This command installs the BNG Blaster to `/usr/sbin/bngblaster`.
|
||||
|
||||
## Build from Sources
|
||||
|
||||
### Dependencies
|
||||
|
||||
The BNG Blaster has dependencies to the RtBrick libdict fork
|
||||
(https://github.com/rtbrick/libdict) and the following standard
|
||||
The BNG Blaster has dependencies to the RtBrick [libdict
|
||||
fork](https://github.com/rtbrick/libdict) and the following standard
|
||||
dependencies:
|
||||
```
|
||||
|
||||
```cli
|
||||
sudo apt install -y cmake \
|
||||
libcunit1-dev \
|
||||
libncurses5-dev \
|
||||
@@ -35,7 +37,8 @@ sudo apt install -y cmake \
|
||||
|
||||
Per default cmake (`cmake .`) will build the BNG Blaster as release
|
||||
version with optimization and without debug symbols.
|
||||
```
|
||||
|
||||
```cli
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
@@ -44,7 +47,8 @@ make all
|
||||
|
||||
Alternative it is also possible to build a debug
|
||||
version for detailed troubleshooting using gdb.
|
||||
```
|
||||
|
||||
```cli
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
@@ -56,12 +60,14 @@ package by just executing `cpack` from build directory.
|
||||
|
||||
It is also recommended to provide the GIT commit details to be included in the
|
||||
manually build version as shown below:
|
||||
```
|
||||
cmake -DGIT_REF=`git rev-parse --abbrev-ref HEAD` -DGIT_SHA=`git rev-parse HEAD` ..
|
||||
|
||||
```cli
|
||||
cmake -DGIT_REF=`git rev-parse --abbrev-ref HEAD` -DGIT_SHA=`git rev-parse HEAD` .
|
||||
```
|
||||
|
||||
*Example:*
|
||||
```
|
||||
|
||||
```cli
|
||||
$ bngblaster -v
|
||||
GIT:
|
||||
REF: dev
|
||||
@@ -72,36 +78,41 @@ IO Modes: packet_mmap_raw (default), packet_mmap, raw
|
||||
### Install
|
||||
|
||||
Then BNG Blaster can be installed using make install target.
|
||||
```
|
||||
|
||||
```cli
|
||||
sudo make install
|
||||
```
|
||||
|
||||
This command installs the BNG Blaster to `/usr/local/sbin/bngblaster`.
|
||||
This command installs the BNG Blaster to `/usr/local/sbin/bngblaster`.
|
||||
|
||||
An existing version installed from debian package in `/usr/sbin` is
|
||||
An existing version installed from debian package in `/usr/sbin` is
|
||||
not automatically replaced or removed here and should be deleted manually
|
||||
before install. Otherwise it might be possible that two versions remain
|
||||
in parallel.
|
||||
```
|
||||
in parallel.
|
||||
|
||||
```cli
|
||||
sudo rm /usr/sbin/bngblaster
|
||||
```
|
||||
|
||||
### Build and Run Unit Tests
|
||||
|
||||
Building and running unit tests requires CMocka to be installed:
|
||||
```
|
||||
|
||||
```cli
|
||||
sudo apt install libcmocka-dev
|
||||
```
|
||||
|
||||
The option `BNGBLASTER_TESTS` enables to build unit tests.
|
||||
```
|
||||
|
||||
```cli
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DBNGBLASTER_TESTS=ON .
|
||||
make all
|
||||
make test
|
||||
```
|
||||
|
||||
*Example*
|
||||
```
|
||||
*Example:*
|
||||
|
||||
```cli
|
||||
$ make test
|
||||
Running tests...
|
||||
Test project
|
||||
@@ -112,3 +123,26 @@ Test project
|
||||
|
||||
Total Test time (real) = 0.00 sec
|
||||
```
|
||||
|
||||
### Running bngblaster
|
||||
|
||||
bngblaster needs permissions to send raw packets and change network interface
|
||||
settings. The easiest way to run bngblaster is either as the root user or with
|
||||
sudo:
|
||||
|
||||
```cli
|
||||
# As root
|
||||
bngblaster -C config.json -I
|
||||
|
||||
# As a normal user:
|
||||
sudo bngblaster -C config.json -I
|
||||
```
|
||||
|
||||
A third option is to set capabilities on the binary with e.g. `setcap`:
|
||||
|
||||
```cli
|
||||
sudo setcap cap_net_raw,cap_net_admin,cap_dac_read_search+eip /path/to/bngblaster
|
||||
|
||||
# As either root or a normal user:
|
||||
bngblaster -C config.json -I
|
||||
```
|
||||
|
||||
@@ -37,14 +37,14 @@
|
||||
nativeBuildInputs = buildTools;
|
||||
|
||||
};
|
||||
bngblaster = pkgs.stdenv.mkDerivation {
|
||||
bngblaster = pkgs.stdenv.mkDerivation rec {
|
||||
pname = "bngblaster";
|
||||
version = "0.52";
|
||||
src = lib.cleanSource ./.;
|
||||
|
||||
doCheck = true;
|
||||
cmakeFlags =
|
||||
[ "-DCMAKE_BUILD_TYPE=Release" "-DBNGBLASTER_TESTS=ON" ];
|
||||
cmakeFlags = [ "-DCMAKE_BUILD_TYPE=Release" ]
|
||||
++ (if doCheck then [ "-DBNGBLASTER_TESTS=ON" ] else [ ]);
|
||||
|
||||
checkInputs = [ pkgs.cmocka pkgs.libpcap ];
|
||||
nativeBuildInputs = buildTools;
|
||||
|
||||
@@ -301,7 +301,7 @@ bbl_add_interface (bbl_ctx_s *ctx, char *interface_name)
|
||||
* Timer to compute periodic rates.
|
||||
*/
|
||||
timer_add_periodic(&ctx->timer_root, &interface->rate_job, "Rate Computation", 1, 0, interface,
|
||||
&bbl_compute_interface_rate_job);
|
||||
&bbl_compute_interface_rate_job);
|
||||
|
||||
return interface;
|
||||
}
|
||||
@@ -606,10 +606,10 @@ main (int argc, char *argv[])
|
||||
bbl_print_usage();
|
||||
exit(0);
|
||||
case 'P':
|
||||
ctx->pcap.filename = optarg;
|
||||
ctx->pcap.filename = optarg;
|
||||
break;
|
||||
case 'J':
|
||||
ctx->config.json_report_filename = optarg;
|
||||
ctx->config.json_report_filename = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
config_file = optarg;
|
||||
@@ -618,7 +618,7 @@ main (int argc, char *argv[])
|
||||
log_enable(optarg);
|
||||
break;
|
||||
case 'L':
|
||||
g_log_file = optarg;
|
||||
g_log_file = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
username = optarg;
|
||||
@@ -645,20 +645,16 @@ main (int argc, char *argv[])
|
||||
interactive = true;
|
||||
break;
|
||||
case 'S':
|
||||
ctx->ctrl_socket_path = optarg;
|
||||
ctx->ctrl_socket_path = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
ctx->config.interface_lock_force = true;
|
||||
ctx->config.interface_lock_force = true;
|
||||
break;
|
||||
default:
|
||||
bbl_print_usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "Error: Must be run with root privileges\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!config_file) {
|
||||
fprintf(stderr, "Error: No configuration specified (-C / --config <file>)\n");
|
||||
|
||||
+41
-17
@@ -62,8 +62,8 @@ bbl_io_packet_mmap_rx_job (timer_s *timer) {
|
||||
|
||||
/* Dump the packet into pcap file. */
|
||||
if (ctx->pcap.write_buf) {
|
||||
pcapng_push_packet_header(ctx, &interface->rx_timestamp, eth_start, eth_len,
|
||||
interface->pcap_index, PCAPNG_EPB_FLAGS_INBOUND);
|
||||
pcapng_push_packet_header(ctx, &interface->rx_timestamp, eth_start, eth_len,
|
||||
interface->pcap_index, PCAPNG_EPB_FLAGS_INBOUND);
|
||||
}
|
||||
|
||||
decode_result = decode_ethernet(eth_start, eth_len, interface->ctx->sp_rx, SCRATCHPAD_LEN, ð);
|
||||
@@ -128,7 +128,7 @@ bbl_io_raw_rx_job (timer_s *timer) {
|
||||
|
||||
while (true) {
|
||||
recv_result = recvfrom(interface->io.fd_rx, interface->io.rx_buf, IO_BUFFER_LEN, 0, &saddr , (socklen_t*)&saddr_size);
|
||||
if(recv_result < 14 || recv_result > IO_BUFFER_LEN) {
|
||||
if(recv_result < 14 || recv_result > IO_BUFFER_LEN) {
|
||||
break;
|
||||
}
|
||||
interface->stats.packets_rx++;
|
||||
@@ -136,8 +136,8 @@ bbl_io_raw_rx_job (timer_s *timer) {
|
||||
|
||||
/* Dump the packet into pcap file. */
|
||||
if (ctx->pcap.write_buf) {
|
||||
pcapng_push_packet_header(ctx, &interface->rx_timestamp, interface->io.rx_buf, interface->io.rx_len,
|
||||
interface->pcap_index, PCAPNG_EPB_FLAGS_INBOUND);
|
||||
pcapng_push_packet_header(ctx, &interface->rx_timestamp, interface->io.rx_buf, interface->io.rx_len,
|
||||
interface->pcap_index, PCAPNG_EPB_FLAGS_INBOUND);
|
||||
}
|
||||
|
||||
decode_result = decode_ethernet(interface->io.rx_buf, interface->io.rx_len, interface->ctx->sp_rx, SCRATCHPAD_LEN, ð);
|
||||
@@ -353,6 +353,36 @@ bbl_io_send (bbl_interface_s *interface, uint8_t *packet, uint16_t packet_len) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Taken and adapted from
|
||||
* https://stackoverflow.com/questions/41678219/how-to-properly-put-network-interface-into-promiscuous-mode-on-linux
|
||||
*
|
||||
* This prevents the ioctl get flags / set flags race condition
|
||||
*/
|
||||
int
|
||||
set_promisc(const char *ifname) {
|
||||
struct packet_mreq mreq = {0};
|
||||
int sfd;
|
||||
|
||||
/* This socket is only opened, but not closed. Closing the socket would reset
|
||||
* its flags - effectively removing the just added promisc mode.
|
||||
* We want to keep the interface in promisc mode until the end of the program.
|
||||
*/
|
||||
if ((sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
|
||||
LOG(ERROR, "unable to open control socket for promisc activation\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mreq.mr_ifindex = if_nametoindex(ifname);
|
||||
mreq.mr_type = PACKET_MR_PROMISC;
|
||||
|
||||
if (mreq.mr_ifindex == 0) {
|
||||
LOG(ERROR, "unable to get interface index for %s\n", ifname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return setsockopt(sfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
}
|
||||
|
||||
/**
|
||||
* bbl_io_add_interface
|
||||
*
|
||||
@@ -364,7 +394,6 @@ bbl_io_add_interface(bbl_ctx_s *ctx, bbl_interface_s *interface) {
|
||||
|
||||
size_t ring_size;
|
||||
char timer_name[32];
|
||||
struct ifreq ifr;
|
||||
int version = TPACKET_V2;
|
||||
int qdisc_bypass = 1;
|
||||
int slots = ctx->config.io_slots;
|
||||
@@ -385,6 +414,10 @@ bbl_io_add_interface(bbl_ctx_s *ctx, bbl_interface_s *interface) {
|
||||
*/
|
||||
interface->io.fd_tx = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0);
|
||||
if (interface->io.fd_tx == -1) {
|
||||
if (errno == EPERM) {
|
||||
LOG(ERROR, "socket() for interface %s Permission denied: Are you root?\n", interface->name);
|
||||
return false;
|
||||
}
|
||||
LOG(ERROR, "socket() TX error %s (%d) for interface %s\n", strerror(errno), errno, interface->name);
|
||||
return false;
|
||||
}
|
||||
@@ -425,18 +458,9 @@ bbl_io_add_interface(bbl_ctx_s *ctx, bbl_interface_s *interface) {
|
||||
}
|
||||
|
||||
/* Set the interface to promiscuous mode. Only for the RX FD. */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface->name);
|
||||
if (ioctl(interface->io.fd_rx, SIOCGIFFLAGS, &ifr) == -1) {
|
||||
LOG(ERROR, "Getting socket flags error %s (%d) when setting promiscuous mode for interface %s\n",
|
||||
strerror(errno), errno, interface->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
ifr.ifr_flags |= IFF_PROMISC;
|
||||
if (ioctl(interface->io.fd_rx, SIOCSIFFLAGS, ifr) == -1){
|
||||
LOG(ERROR, "Setting socket flags error %s (%d) when setting promiscuous mode for interface %s\n",
|
||||
strerror(errno), errno, interface->name);
|
||||
if (set_promisc(interface->name) != 0) {
|
||||
LOG(ERROR, "Failed to put interface %s in promiscuous mode\n", interface->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -34,14 +34,14 @@ bbl_stream_can_send(bbl_stream *stream) {
|
||||
}
|
||||
break;
|
||||
case STREAM_IPV6:
|
||||
if(session->ip6cp_state == BBL_PPP_OPENED &&
|
||||
session->icmpv6_ra_received &&
|
||||
if(session->ip6cp_state == BBL_PPP_OPENED &&
|
||||
session->icmpv6_ra_received &&
|
||||
*(uint64_t*)session->ipv6_address) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case STREAM_IPV6PD:
|
||||
if(session->ip6cp_state == BBL_PPP_OPENED &&
|
||||
if(session->ip6cp_state == BBL_PPP_OPENED &&
|
||||
session->icmpv6_ra_received &&
|
||||
*(uint64_t*)session->delegated_ipv6_address &&
|
||||
session->dhcpv6_state >= BBL_DHCP_BOUND) {
|
||||
@@ -59,7 +59,7 @@ bbl_stream_can_send(bbl_stream *stream) {
|
||||
}
|
||||
break;
|
||||
case STREAM_IPV6:
|
||||
if(*(uint64_t*)session->ipv6_address &&
|
||||
if(*(uint64_t*)session->ipv6_address &&
|
||||
session->icmpv6_ra_received) {
|
||||
return true;
|
||||
}
|
||||
@@ -565,6 +565,10 @@ bbl_stream_tx_thread (void *thread_data) {
|
||||
/* Open new TX socket for thread. */
|
||||
fd_tx = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0);
|
||||
if (fd_tx == -1) {
|
||||
if (errno == EPERM) {
|
||||
LOG(ERROR, "socket() for interface %s Permission denied: Are you root?\n", interface->name);
|
||||
return NULL;
|
||||
}
|
||||
LOG(ERROR, "socket() TX error %s (%d) for interface %s\n", strerror(errno), errno, interface->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user