diff --git a/.github/workflows/quick.yml b/.github/workflows/quick.yml index f3da7c5..61d2061 100644 --- a/.github/workflows/quick.yml +++ b/.github/workflows/quick.yml @@ -36,7 +36,7 @@ jobs: smoketest_all_opts: name: Smoke test With all options turned on - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -75,7 +75,7 @@ jobs: - name: Generate coverage reports run: | make gcov - make cover COVERAGEDIR=coverage/ubuntu-latest + make cover COVERAGEDIR=coverage/ubuntu-22.04 shell: bash - name: Upload gcovr report artifact @@ -114,7 +114,7 @@ jobs: lint: name: Code syntax - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/doc/Containerfile.example b/doc/Containerfile.example new file mode 100644 index 0000000..f284117 --- /dev/null +++ b/doc/Containerfile.example @@ -0,0 +1,46 @@ +# +# A simple example of how to build a docker container for n3n-edge +# +# Build with the command: +# podman build \ +# --device=/dev/net/tun \ +# --cap-add=NET_ADMIN \ +# -t=n3n \ +# -f doc/Containerfile.example \ +# . +# +# Start a n3n session with: +# podman run \ +# -it \ +# --name=n3n \ +# --device=/dev/net/tun \ +# --cap-add=NET_ADMIN \ +# -v $PWD/n3n:/etc/n3n/ \ +# n3n start -vvvv +# +# Note that the build could be done without the --device and --cap-add if +# the `make test` is omitted + +FROM docker.io/library/debian:12 AS builder + +RUN apt-get update +RUN apt-get install -y build-essential autoconf git python3 jq sudo + +WORKDIR /n3n + +COPY . . + +RUN \ + ./autogen.sh && \ + ./configure && \ + make clean all && \ + make test + + +FROM docker.io/library/debian:12 + +COPY --from=builder /n3n/apps/n3n-edge /n3n-edge + +VOLUME [ "/etc/n3n" ] +ENTRYPOINT ["/n3n-edge"] +CMD ["start"] diff --git a/libs/connslot/connslot.c b/libs/connslot/connslot.c index b0382c7..03f0ce4 100644 --- a/libs/connslot/connslot.c +++ b/libs/connslot/connslot.c @@ -177,7 +177,7 @@ void conn_check_ready(conn_t *conn) { return; } -void conn_read(conn_t *conn, int fd) { +ssize_t conn_read(conn_t *conn, int fd) { conn->state = CONN_READING; // If no space available, try increasing our capacity @@ -195,28 +195,26 @@ void conn_read(conn_t *conn, int fd) { // zero-sized read request, the only time we get a zero back is if the // far end has closed conn->state = CONN_CLOSED; - return; + return 0; } if (size == -1) { if (errno == EWOULDBLOCK || errno == EAGAIN) { - conn->state = CONN_EMPTY; - return; + return 0; } conn->state = CONN_ERROR; - return; + return 0; } // This will truncate the time to a int - usually 32bits conn->activity = time(NULL); conn_check_ready(conn); + return size; } ssize_t conn_write(conn_t *conn, int fd) { ssize_t sent; - conn->state = CONN_SENDING; - if (fd == -1) { return 0; } @@ -267,11 +265,17 @@ ssize_t conn_write(conn_t *conn, int fd) { unsigned int end_pos = sb_len(conn->reply_header) + sb_len(conn->reply); #endif + if (sent == -1) { + sent = 0; + if (errno != EAGAIN && errno != EWOULDBLOCK) { + conn->state = CONN_ERROR; + } + } + conn->reply_sendpos += sent; if (conn->reply_sendpos >= end_pos) { // We have sent the last bytes of this reply - conn->state = CONN_EMPTY; conn->reply_sendpos = 0; sb_zero(conn->reply_header); sb_zero(conn->reply); @@ -282,13 +286,20 @@ ssize_t conn_write(conn_t *conn, int fd) { return sent; } -int conn_iswriter(conn_t *conn) { - switch (conn->state) { - case CONN_SENDING: - return 1; - default: - return 0; +bool conn_iswriter(conn_t *conn) { + int endpos = 0; + if (conn->reply_header) { + endpos += sb_len(conn->reply_header); + } + if (conn->reply) { + endpos += sb_len(conn->reply); } + + // If there are any bytes ready to send, then we are writable + if(endpos) { + return true; + } + return false; } void conn_close(conn_t *conn, int fd) { diff --git a/libs/connslot/connslot.h b/libs/connslot/connslot.h index fc24325..f710106 100644 --- a/libs/connslot/connslot.h +++ b/libs/connslot/connslot.h @@ -29,7 +29,6 @@ enum __attribute__((__packed__)) conn_state { CONN_EMPTY = 0, CONN_READING = 1, CONN_READY = 2, - CONN_SENDING = 3, CONN_CLOSED = 4, CONN_ERROR = 5, }; @@ -64,9 +63,9 @@ void conn_zero(conn_t *); int conn_init(conn_t *, size_t, size_t); void conn_accept(conn_t *, int, enum conn_proto); void conn_check_ready(conn_t *); -void conn_read(conn_t *, int); +ssize_t conn_read(conn_t *, int); ssize_t conn_write(conn_t *, int); -int conn_iswriter(conn_t *); +bool conn_iswriter(conn_t *); void conn_close(conn_t *, int); bool conn_closeidle(conn_t *, int, int, int); void conn_dump(strbuf_t **, conn_t *); diff --git a/src/edge_utils.c b/src/edge_utils.c index e92efbb..151db20 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -1630,11 +1630,13 @@ void update_supernode_reg (struct n3n_runtime_data * eee, time_t now) { if(eee->conf.bind_address) { // do not explicitly disconnect every time as the condition described is rare, so ... // ... check that there are no external peers (indicating a working socket) ... - HASH_ITER(hh, eee->known_peers, peer, tmp_peer) - if(!peer->local) { - cnt++; - break; + HASH_ITER(hh, eee->known_peers, peer, tmp_peer) { + if(!peer->local) { + cnt++; + break; + } } + if(!cnt) { // ... and then count the connection retries (eee->close_socket_counter)++; @@ -2297,7 +2299,7 @@ void process_udp (struct n3n_runtime_data *eee, via_multicast = (in_sock == eee->udp_multicast_sock); #endif - traceEvent(TRACE_DEBUG, "Rx N2N_UDP of size %d from [%s]", + traceEvent(TRACE_DEBUG, "Rx VPN packet of size %d from [%s]", (signed int)udp_size, sock_to_cstr(sockbuf1, &sender)); if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { diff --git a/src/mainloop.c b/src/mainloop.c index 5bc7ab9..cf6aff0 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -226,6 +226,10 @@ static int fdlist_allocslot (int fd, enum fd_info_proto proto) { static void fdlist_freefd (int fd) { int slot = 0; + if(fd == -1) { + // Cannot release an error fd! + return; + } while(slot < MAX_HANDLES) { if(fdlist[slot].fd != fd) { slot++; @@ -331,7 +335,6 @@ static void handle_fd (const time_t now, const struct fd_info info, struct n3n_r switch(conn->state) { case CONN_EMPTY: case CONN_READING: - case CONN_SENDING: // These states dont require us to do anything // TODO: // - handle reading/sending simultaneous? @@ -402,7 +405,6 @@ static void handle_fd (const time_t now, const struct fd_info info, struct n3n_r switch(conn->state) { case CONN_EMPTY: case CONN_READING: - case CONN_SENDING: // These states dont require us to do anything // TODO: // - handle reading/sending simultaneous? diff --git a/src/n2n.c b/src/n2n.c index 2101643..9c99d0a 100644 --- a/src/n2n.c +++ b/src/n2n.c @@ -62,8 +62,41 @@ SOCKET open_socket (struct sockaddr *local_address, socklen_t addrlen, int type /* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */ #endif + int result; + sockopt = 1; - setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)); + result = setsockopt( + sock_fd, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&sockopt, + sizeof(sockopt) + ); + if(result == -1) { + traceEvent( + TRACE_ERROR, + "SO_REUSEADDR fd=%i, error=%s\n", + sock_fd, + strerror(errno) + ); + } +#ifdef SO_REUSEPORT /* no SO_REUSEPORT in Windows / old linux versions */ + result = setsockopt( + sock_fd, + SOL_SOCKET, + SO_REUSEPORT, + (char *)&sockopt, + sizeof(sockopt) + ); + if(result == -1) { + traceEvent( + TRACE_ERROR, + "SO_REUSEPORT fd=%i, error=%s\n", + sock_fd, + strerror(errno) + ); + } +#endif if(!local_address) { // skip binding if we dont have the right details diff --git a/tools/crypto_helper.c b/tools/crypto_helper.c index f1a47e3..0bea38f 100644 --- a/tools/crypto_helper.c +++ b/tools/crypto_helper.c @@ -96,7 +96,10 @@ static void cmd_header_decrypt (int argc, char **argv, void *conf) { exit(1); } - write(1, &buf, size); + int r = write(1, &buf, size); + if(r != size) { + printf("Short write\n"); + } exit(0); } @@ -130,7 +133,10 @@ static void cmd_pearson_128 (int argc, char **argv, void *conf) { unsigned char hash[16]; size = read(0, &buf, sizeof(buf)); pearson_hash_128(hash, buf, size); - write(1, &hash, sizeof(hash)); + int r = write(1, &hash, sizeof(hash)); + if(r != sizeof(hash)) { + printf("Short write\n"); + } exit(0); }