aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/include/defs.h3
-rw-r--r--lib/include/net/stpsession.h50
-rw-r--r--lib/include/otconfig.h1
-rw-r--r--lib/include/server.h1
-rw-r--r--lib/libostp/auth.c95
-rw-r--r--lib/libostp/server.c1
-rw-r--r--lib/libostp/session.c42
7 files changed, 191 insertions, 2 deletions
diff --git a/lib/include/defs.h b/lib/include/defs.h
index a15a2fd..d4a57a9 100644
--- a/lib/include/defs.h
+++ b/lib/include/defs.h
@@ -58,4 +58,7 @@
/* Fixed paths */
#define OSMORA_TRUST "/etc/ostp/trusted_users.osmt"
+/* Maximum length of an IP */
+#define IP_LEN_MAX 46
+
#endif
diff --git a/lib/include/net/stpsession.h b/lib/include/net/stpsession.h
index 731b8ce..9735678 100644
--- a/lib/include/net/stpsession.h
+++ b/lib/include/net/stpsession.h
@@ -46,6 +46,17 @@
/* Session Request option bits */
#define SESSION_REQ_USER BIT(0)
+#define SESSION_REQ_P2P BIT(1)
+
+/*
+ * For ACKing/TRUNCing packets e.g.,
+ * peer blocks
+ */
+#define ACK_WORD 0xAC7E
+#define TRUNC_WORD 0x782C
+
+#define PB_N_PEERS 16
+#define PB_N_BLOCKS 16
/*
* The Session Request is sent from the client to the
@@ -63,11 +74,12 @@
* /
* 0 1 2 3 4 5 6
* ~ ~ ~ ~ ~ ~ ~
- * U R R R R R R
+ * U P R R R R R
* \
* Purpose
*
* U: User auth.
+ * P: Peer-to-peer.
* R: Reserved, keep zero.
*/
struct session_request {
@@ -77,6 +89,42 @@ struct session_request {
} PACKED;
/*
+ * The `peer' structure describes a peer on
+ * an OSTP server running in peer-to-peer mode.
+ *
+ * @pad: Must be all 1s, treat invalid otherwise
+ * @port: Port peer accepts connections on
+ * @host: Host peer is at
+ */
+struct peer {
+ uint8_t pad[1];
+ uint16_t port;
+ char host[IP_LEN_MAX];
+};
+
+/*
+ * If P2P is enabled and supported, the OCS
+ * sends one or more peer blocks in a consecutive
+ * manner. Each peer block can list up to 16 peers
+ * max. If the `seq' field is greater than zero and
+ * the list of peers within the current block is full,
+ * the client may either request the next peer block by
+ * sending an ACK packet or terminating the connection
+ * by sending a TRUNC packet.
+ *
+ * @peers: List of available peers within this block
+ * @seq: Descending one-based block sequence number (0=invalid)
+ */
+struct peer_block {
+ struct peer peers[PB_N_PEERS];
+ uint8_t seq;
+} PACKED;
+
+/* Peer/block counts must be powers of two */
+CTASSERT((PB_N_PEERS & 1) == 0, "PB_N_PEERS not power-of-two!");
+CTASSERT((PB_N_BLOCKS & 1) == 0, "PB_N_BLOCKS not power-of-two!");
+
+/*
* Structure containing user information
* for password protected channels.
*/
diff --git a/lib/include/otconfig.h b/lib/include/otconfig.h
index 96cac38..e8400b1 100644
--- a/lib/include/otconfig.h
+++ b/lib/include/otconfig.h
@@ -34,6 +34,7 @@
#define DIAGNOSTIC 0 /* 1 for verbosity */
#define CONNECTION_TIMEOUT 60 /* In seconds */
#define ENABLE_MOTD 1 /* Enable message of the day */
+#define ENABLE_P2P 1 /* Enable peer-to-peer sessions */
#define ARBITRATION_MAX 5 /* Maximum number of arbitration attempts */
#define REQUIRE_USER_AUTH 1 /* 1: true, 0: false */
#define OSTP_PORT 5352
diff --git a/lib/include/server.h b/lib/include/server.h
index c8eff9c..33d2b7e 100644
--- a/lib/include/server.h
+++ b/lib/include/server.h
@@ -40,6 +40,7 @@
struct ostp_client {
struct ostp_session session;
+ char host[IP_LEN_MAX];
int sockfd;
pthread_t td;
volatile uint8_t authed : 1;
diff --git a/lib/libostp/auth.c b/lib/libostp/auth.c
index 5fa59e9..ddc17b8 100644
--- a/lib/libostp/auth.c
+++ b/lib/libostp/auth.c
@@ -30,8 +30,10 @@
#include <sys/wait.h>
#include <sys/socket.h>
#include <ostp/net/auth.h>
+#include <ostp/net/stpsession.h>
#include <ostp/crypto/ecdh.h>
#include <ostp/otconfig.h>
+#include <ostp/defs.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
@@ -133,6 +135,78 @@ send_motd(struct ostp_client *c, const unsigned char *session_key)
}
}
+static inline void
+populate_peer(struct ostp_client *c, struct peer *pp)
+{
+ memset(pp, 0, sizeof(*pp));
+ pp->port = htons(OSTP_PORT);
+ pp->pad[0] = 0xFF;
+ memcpy(pp->host, c->host, IP_LEN_MAX);
+}
+
+static int
+send_peerlist(struct ostp_listener *lp, struct ostp_client *c, struct ostp_session *s)
+{
+ struct ostp_client *c_cur, *c_tmp;
+ struct peer peer_cur;
+ struct peer_block pb_cur;
+ struct ostp_session *sp;
+ size_t peer_count;
+ int i, j, error;
+ int seq;
+
+ memset(&pb_cur, 0, sizeof(pb_cur));
+ peer_count = lp->client_count;
+ seq = (peer_count <= 16) ? 1 : (peer_count / PB_N_PEERS);
+ pb_cur.seq = seq;
+ printf("peer_count=%d, seq=%d\n", peer_count, pb_cur.seq);
+
+ /*
+ * Grab peers and prepare blocks until seq == 0
+ *
+ *
+ * lp->clients
+ * +-------------------+
+ * i=| | | | | | | | | | |
+ * +-------------------+
+ * 0,1,2,3,4,5,6,7,8,9 <--+
+ * |
+ * pb_cur.peers |
+ * +---------------+ | lp->clients can be bigger
+ * j=| | | | | | | | | |
+ * +---------------+ +
+ * 0,1,2,3,4,5,6,7 <---+-/
+ *
+ *
+ * lp->clients is one big contigious array
+ * of connected clients and is used internally
+ * by the server to manage connected users.
+ *
+ * During a session request, the client may request
+ * peer-to-peer mode by setting the 'P' bit. If accepted,
+ * we'll need to send one or more peer blocks back, containing
+ * a list of `PB_N_PEERS' peers max per block.
+ *
+ */
+ for (i = 0; i < PB_N_BLOCKS && seq > 0; ++i) {
+ for (j = 1; j < PB_N_PEERS && j < peer_count; ++j) {
+ populate_peer(&lp->clients[j], &peer_cur);
+ pb_cur.peers[j] = peer_cur;
+ }
+
+ --seq;
+ pb_cur.seq = seq;
+ sp = &c->session;
+ session_send(&pb_cur, sizeof(pb_cur), sp);
+
+ if (j >= lp->client_count) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
int
handle_srq(struct ostp_client *c, struct ostp_listener *lp, struct session_request *srq)
{
@@ -140,12 +214,20 @@ handle_srq(struct ostp_client *c, struct ostp_listener *lp, struct session_reque
struct ostp_session *session;
int error;
+ /* Do we require the SRQ 'U' bit? */
if (REQUIRE_USER_AUTH && !ISSET(srq->options, SESSION_REQ_USER)) {
printf("User authentication enforced but client 'U' bit not set\n");
printf("Closing connection...\n");
return -1;
}
+ /* Don't use P2P if not enabled */
+ if (!ENABLE_P2P && !ISSET(srq->options, SESSION_REQ_P2P)) {
+ printf("P2P not enabled but client 'P' bit set\n");
+ printf("Closing connection...\n");
+ return -1;
+ }
+
/* Generate a new keypair if we have no link */
if (!g_have_link) {
if (gen_x25519_keypair(&keypair) < 0) {
@@ -183,6 +265,19 @@ handle_srq(struct ostp_client *c, struct ostp_listener *lp, struct session_reque
return -1;
}
+ /* Handle P2P requests */
+ if (ISSET(srq->options, SESSION_REQ_P2P)) {
+ /*
+ * Not an error but we want to send this down
+ * the callstack so everything is cleaned up
+ * and terminated properly.
+ *
+ * TODO: Figure something else out here maybe...
+ */
+ send_peerlist(lp, c, session);
+ return -1;
+ }
+
/* Handle any requested session parameters */
if ((error = negotiate_spw(c, session->session_key)) < 0) {
free_session_key(session->session_key);
diff --git a/lib/libostp/server.c b/lib/libostp/server.c
index 794eda0..61e89f7 100644
--- a/lib/libostp/server.c
+++ b/lib/libostp/server.c
@@ -199,6 +199,7 @@ listener_poll(struct ostp_listener *lp)
++lp->client_count;
ip = inet_ntoa(caddr.sin_addr);
+ memcpy(c->host, ip, strlen(ip) + 1);
printf("Incoming connection from %s\n", ip);
handle_client(&caddr, c, lp);
break;
diff --git a/lib/libostp/session.c b/lib/libostp/session.c
index 3843207..b61600f 100644
--- a/lib/libostp/session.c
+++ b/lib/libostp/session.c
@@ -193,6 +193,35 @@ recv_motd(int sockfd, const unsigned char *session_key)
printf("%s\n", buf);
}
+static void
+recv_peers(int sockfd, const unsigned char *session_key)
+{
+ struct peer_block pb;
+ struct peer peer;
+ int i, len;
+
+ memset(&pb, 0, sizeof(pb));
+ memset(&peer, 0, sizeof(peer));
+
+ /* Receive the peer block the server sends back */
+ if ((len = recv_frame(sockfd, sizeof(pb), session_key, &pb)) < 0) {
+ printf("Failed to recv peers...\n");
+ return;
+ }
+
+ printf("Got %d bytes...\n", len);
+ printf("seq=%x\n", pb.seq);
+
+ for (i = 0; i < PB_N_PEERS; ++i) {
+ peer = pb.peers[i];
+ if (peer.pad[0] != 0xFF) {
+ continue;
+ }
+
+ printf("Peer available @ %s:%d\n", peer.host, peer.port);
+ }
+}
+
int
session_new(const char *host, struct ostp_session *res)
{
@@ -233,7 +262,7 @@ session_new(const char *host, struct ostp_session *res)
* Setup the session request and add our public
* key to it. We also assume user authentication.
*/
- stp_sq.options = SESSION_REQ_USER;
+ stp_sq.options = (SESSION_REQ_USER | SESSION_REQ_P2P);
memcpy(stp_sq.pubkey, keypair.pubkey, sizeof(stp_sq.pubkey));
LOG("Sending session request...\n");
@@ -266,6 +295,17 @@ session_new(const char *host, struct ostp_session *res)
return error;
}
+ /*
+ * If we requested P2P, the server will respond
+ * with peer blocks.
+ */
+ if (ISSET(stp_sq.options, SESSION_REQ_P2P)) {
+ recv_peers(sockfd, session_key);
+ free_session_key(session_key);
+ close(sockfd);
+ return 0;
+ }
+
/* Send server SPW bits */
if ((error = client_negotiate_spw(sockfd, session_key)) < 0) {
LOG("Session Parameter Negotiation failed\n");