about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorRen Kararou <[email protected]>2025-01-07 20:52:27 -0600
committerRen Kararou <[email protected]>2025-01-07 20:52:27 -0600
commit660da53647cdcdc5ce07054f74e5c420a15702fe (patch)
tree796f00487c00a16a958467860354ad9f4bcc0276
parentb9635ce3b4ca30b14128c131bb9fe9be08740d6d (diff)
downloadnbtpd-660da53647cdcdc5ce07054f74e5c420a15702fe.tar.gz
nbtpd-660da53647cdcdc5ce07054f74e5c420a15702fe.tar.bz2
nbtpd-660da53647cdcdc5ce07054f74e5c420a15702fe.zip
first RRQ processed
-rw-r--r--inc/handlers.h2
-rw-r--r--inc/packet.h5
-rw-r--r--src/handlers.c122
-rw-r--r--src/main.c33
-rw-r--r--src/packet.c39
5 files changed, 178 insertions, 23 deletions
diff --git a/inc/handlers.h b/inc/handlers.h
index aecd964..acf994e 100644
--- a/inc/handlers.h
+++ b/inc/handlers.h
@@ -10,7 +10,7 @@
 typedef enum opmode {
 	NOT_FOUND,
 	NETASCII,
-	OCTAL,
+	OCTET,
 	MAIL
 // any additional modes
 } nbd_opmode;
diff --git a/inc/packet.h b/inc/packet.h
index abd6d3e..a404d49 100644
--- a/inc/packet.h
+++ b/inc/packet.h
@@ -2,6 +2,7 @@
 #define NBD_TFTP_PACKET_H
 
 #include <stdint.h>
+#include <unistd.h>
 
 typedef enum {
 	RRQ	= 1,
@@ -32,6 +33,7 @@ typedef struct {
 	uint16_t opcode;
 	uint16_t block_num;
 	char *data;
+	size_t datalen;
 } nbd_tftp_packet_data;
 
 typedef struct {
@@ -46,6 +48,9 @@ typedef struct {
 } nbd_tftp_packet_error;
 
 char *nbd_tftp_error_to_message(nbd_tftp_ecode error);
+char *nbd_tftp_ser_data(nbd_tftp_packet_data d);
+char *nbd_tftp_ser_data_from_parts(uint16_t blocknum, char *data, size_t datalen);
+nbd_tftp_packet_ack nbd_tftp_de_ack(char *buf, ssize_t buflen);
 
 #endif
 
diff --git a/src/handlers.c b/src/handlers.c
index fdd16f8..394ccb0 100644
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -24,8 +24,8 @@ nbd_opmode get_mode(char *mode) {
 	nbd_opmode opmode;
 	if (strncmp(mode, (char *)&"netascii", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
 		opmode = NETASCII;
-	} else if (strncmp(mode, (char *)&"octal", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
-		opmode = OCTAL;
+	} else if (strncmp(mode, (char *)&"octet", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
+		opmode = OCTET;
 	} else if (strncmp(mode, (char *)&"mail", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
 		opmode = MAIL;
 	} else {
@@ -35,9 +35,10 @@ nbd_opmode get_mode(char *mode) {
 }
 
 void *read_req_resp(void *args) {
-	char *fname = NULL, *wd = NULL, *buf = NULL;
+	char *fname = NULL, *wd = NULL, *buf = NULL, *rxb = NULL;
 	FILE *fp = NULL;
 	nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args;
+	syslog(LOG_DEBUG, "%s:%d is requesting file %s", inet_ntoa(argptr->client.sin_addr), ntohs(argptr->client.sin_port), argptr->path);
 	if (!is_netascii_str((char *)&argptr->path)) {
 		argptr->err = 1;
 		goto pre_socket;
@@ -71,21 +72,46 @@ void *read_req_resp(void *args) {
 		goto pre_socket;
 	}
 #endif
-	if (!strncmp(wd, fname, sizeof(wd) - 1)) {
+	syslog(LOG_DEBUG, "cwd: %s :: realpath: %s", wd, fname);
+	if (strncmp(wd, fname, strlen(wd))) {
+		syslog(
+			LOG_ERR,
+			"%s:%d requested invalid file %s",
+			inet_ntoa(argptr->client.sin_addr),
+			ntohs(argptr->client.sin_port),
+			fname
+		);
 		argptr->err = 2;
 		goto pre_socket;
 	}
-	if (!is_netascii_str((char *)&argptr->mode)) {
+	if (!is_netascii_str((char *)&(argptr->mode))) {
+		syslog(
+			LOG_ERR,
+			"%s:%d mode is invalid %s",
+			inet_ntoa(argptr->client.sin_addr),
+			ntohs(argptr->client.sin_port),
+			argptr->mode
+		);
 		argptr->err = 4;
 		goto pre_socket;
 	}
-	nbd_opmode opmode = get_mode((char *)&argptr->mode);
-	if ((opmode != NETASCII) && (opmode != OCTAL)) {
+	nbd_opmode opmode = get_mode((char *)&(argptr->mode));
+	if ((opmode != NETASCII) && (opmode != OCTET)) {
 		argptr->err = 4;
 		goto pre_socket;
 	}
 	fp = fopen(fname, "r");
+	if (fp == NULL) {
+		syslog(
+			LOG_ERR,
+			"failed to open file for reading: %s",
+			strerror(errno)
+		);
+		argptr->err = 2;
+		goto pre_socket;
+	}
 	buf = malloc(512);
+	rxb = malloc(256);
 	if (buf == NULL) {
 		syslog(
 			LOG_CRIT,
@@ -95,13 +121,17 @@ void *read_req_resp(void *args) {
 		argptr->err = 0;
 		goto pre_socket;
 	}
-	memset(buf, '\0', 512);
 	int s = socket(AF_INET, SOCK_DGRAM, 0);
 	if (s <= 0) {
 		syslog(LOG_ERR, "unable to define socket: %s", strerror(errno));
 		goto cleanup;
 	}
-	if (connect(s, (struct sockaddr *)&argptr->client, sizeof(struct sockaddr)) < 0) {
+	struct timeval timeout = { 30, 0 };
+	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
+		syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno));
+		goto socket_clean;
+	}
+	if (connect(s, (struct sockaddr *)&(argptr->client), sizeof(struct sockaddr)) < 0) {
 		syslog(
 			LOG_ERR,
 			"unable to connect to client %s: %s",
@@ -110,12 +140,82 @@ void *read_req_resp(void *args) {
 		);
 		goto socket_clean;
 	}
-
+	uint8_t rxon = 0, lon = 1;
+	uint16_t bnum = 0;
+	while (lon) {
+		memset(buf, '\0', 512);
+		uint8_t verif = 0;
+		uint8_t vcount = 0;
+		size_t num_read = fread(buf, 1, 512, fp);
+		if (((num_read < 512) && (!feof(fp))) || (vcount > 5)) {
+			//TODO: error response function!
+		}
+		char *packet = nbd_tftp_ser_data_from_parts(++bnum, buf, num_read);
+		while (!verif) {
+			syslog(LOG_DEBUG, "sending block number %d to %s:%d",
+				bnum,
+				inet_ntoa(argptr->client.sin_addr),
+				htons(argptr->client.sin_port)
+			);
+			if (send(s, packet, num_read + 4, 0) < 0) {
+				syslog(
+					LOG_ERR,
+					"unable to send data to %s: %s",
+					inet_ntoa(argptr->client.sin_addr),
+					strerror(errno)
+				);
+				continue;
+			}
+			rxon = 1;
+			uint8_t rxcount = 0;
+			while (rxon) {
+				syslog(LOG_DEBUG, "waiting for ack %d from %s:%d",
+					bnum,
+					inet_ntoa(argptr->client.sin_addr),
+					htons(argptr->client.sin_port)
+				);
+				memset(rxb, '\0', 256);
+				ssize_t rcv = recv(s, rxb, 256, 0);
+				syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d",
+					rcv,
+					inet_ntoa(argptr->client.sin_addr),
+					htons(argptr->client.sin_port)
+				);
+				if (rcv == 4) {
+					nbd_tftp_packet_ack ack = nbd_tftp_de_ack(rxb, rcv);
+					syslog(LOG_DEBUG, "%s:%d ack'd with block number: %d (expect %d)",
+						inet_ntoa(argptr->client.sin_addr),
+						htons(argptr->client.sin_port),
+						ack.block_num,
+						bnum
+					);
+					if (ack.block_num == bnum) {
+						rxon = 0;
+						verif = 1;
+						break;
+					}
+					if (ack.block_num == (bnum - 1)) {
+						rxon = 0;
+						vcount++;
+						break;
+					}
+				}
+				if (++rxcount > 30) {
+					//TODO: error response function!
+				}
+			}
+		}
+		free(packet);
+		if (num_read < 512) {
+			lon = 0;
+		}
+	}
 socket_clean:
 	close(s);
 cleanup:
 	fclose(fp);
 	free(buf);
+	free(rxb);
 	free(fname);
 	free(wd);
 	free(args);
@@ -125,6 +225,7 @@ pre_socket:
 		fclose(fp);
 	}
 	free(buf);
+	free(rxb);
 	free(fname);
 	free(wd);
 	return nbd_nbtpd_resp_error(args);
@@ -137,6 +238,7 @@ void *write_req_resp(void *args) {
 
 void *nbd_nbtpd_resp_error(void *args) {
 	//TODO: open socket and scream error, then cleanup.
+	//TODO: error response function!
 	free(args);
 	return (void *)NULL;
 }
diff --git a/src/main.c b/src/main.c
index c36bc9a..fc5835b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -64,35 +64,35 @@ void usage(char *name) {
 }
 
 int set_loglevel(char *level) {
-	if (strncmp("emerg", level, 6) != 0) {
+	if (strncmp("emerg", level, 6) == 0) {
 		setlogmask(LOG_UPTO(LOG_EMERG));
 		return 0;
 	}
-	if (strncmp("alert", level, 6) != 0) {
+	if (strncmp("alert", level, 6) == 0) {
 		setlogmask(LOG_UPTO(LOG_ALERT));
 		return 0;
 	}
-	if (strncmp("crit", level, 5) != 0) {
+	if (strncmp("crit", level, 5) == 0) {
 		setlogmask(LOG_UPTO(LOG_CRIT));
 		return 0;
 	}
-	if (strncmp("err", level, 4) != 0) {
+	if (strncmp("err", level, 4) == 0) {
 		setlogmask(LOG_UPTO(LOG_ERR));
 		return 0;
 	}
-	if (strncmp("warn", level, 5) != 0) {
+	if (strncmp("warn", level, 5) == 0) {
 		setlogmask(LOG_UPTO(LOG_WARNING));
 		return 0;
 	}
-	if (strncmp("notice", level, 7) != 0) {
+	if (strncmp("notice", level, 7) == 0) {
 		setlogmask(LOG_UPTO(LOG_NOTICE));
 		return 0;
 	}
-	if (strncmp("info", level, 5) != 0) {
+	if (strncmp("info", level, 5) == 0) {
 		setlogmask(LOG_UPTO(LOG_INFO));
 		return 0;
 	}
-	if (strncmp("debug", level, 6) != 0) {
+	if (strncmp("debug", level, 6) == 0) {
 		setlogmask(LOG_UPTO(LOG_DEBUG));
 		return 0;
 	}
@@ -144,7 +144,7 @@ int main(int argc, char **argv) {
 				break;
 			case 'l':
 				loglevset = 1;
-				if (!set_loglevel(optarg)) {
+				if (set_loglevel(optarg)) {
 					fprintf(stderr, "invalid option for -l\n");
 					usage(argv[0]);
 					return -1;
@@ -181,7 +181,7 @@ int main(int argc, char **argv) {
 			syslog(LOG_INFO, "daemonized");
 		}
 	}
-	struct timeval timeout = { 1, 0 };
+	struct timeval timeout = { 30, 0 };
 	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
 		syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno));
 		retme = -1;
@@ -196,7 +196,7 @@ int main(int argc, char **argv) {
 		retme = -1;
 		goto cleanup;
 	}
-	syslog(LOG_INFO, "socket bind success");
+	syslog(LOG_DEBUG, "socket bind success");
 	if (daemonize) {
 		//TODO: use getpwnam_r() and getgrnam_r()
 		struct group *g = getgrnam((const char *)&group);
@@ -246,6 +246,12 @@ int main(int argc, char **argv) {
 			);
 			continue;
 		}
+		syslog(
+			LOG_INFO,
+			"got connection from %s:%d",
+			inet_ntoa(caddr.sin_addr),
+			ntohs(caddr.sin_port)
+		);
 		nbd_nbtpd_args *args = malloc(sizeof(nbd_nbtpd_args));
 		if (args == NULL) {
 			syslog(
@@ -255,7 +261,7 @@ int main(int argc, char **argv) {
 			);
 			continue;
 		}
-		nbd_tftp_opcode oc = ntohs(((uint16_t)buf[0] << 8) + buf[1]);
+		nbd_tftp_opcode oc = ((uint16_t)buf[0] << 8) + buf[1];
 		args->client = caddr;
 		args->err = 0;
 		memset(args->path, '\0', NBD_NBTPD_ARGS_PATH_MAX);
@@ -293,6 +299,9 @@ int main(int argc, char **argv) {
 		}
 		//TODO: use std threads
 		int e;
+		syslog(LOG_ERR, "spawning thread for %s", inet_ntoa(caddr.sin_addr));
+//		void *lol = func((void *)args);
+//		free(lol);
 		if ((e = pthread_create(_thread, 0, func, (void *)args)) != 0) {
 			syslog(
 				LOG_CRIT,
diff --git a/src/packet.c b/src/packet.c
index 5bc8be6..0c9d592 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -1,3 +1,7 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <string.h>
 #include "packet.h"
 
 char *nbd_tftp_error_to_message(nbd_tftp_ecode error) {
@@ -22,3 +26,38 @@ char *nbd_tftp_error_to_message(nbd_tftp_ecode error) {
 	return "UNKNOWN ERROR";
 }
 
+char *nbd_tftp_ser_data(nbd_tftp_packet_data d) {
+	char *buf = malloc(sizeof(d.opcode) + sizeof(d.block_num) + d.datalen);
+	if (buf != NULL) {
+		uint16_t netopcode = htons(d.opcode);
+		uint16_t netbnum = htons(d.block_num);
+		memcpy(buf, &netopcode, sizeof(netopcode));
+		memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum));
+		memcpy((buf + sizeof(netopcode) + sizeof(netbnum)), d.data, d.datalen);
+	}
+	return buf;
+}
+
+char *nbd_tftp_ser_data_from_parts(uint16_t blocknum, char *data, size_t datalen) {
+	char *buf = malloc(sizeof(uint16_t) + sizeof(blocknum) + datalen);
+	if (buf != NULL) {
+		uint16_t netopcode = htons(3);
+		uint16_t netbnum = htons(blocknum);
+		memcpy(buf, &netopcode, sizeof(netopcode));
+		memcpy((buf + sizeof(netopcode)), &netbnum, sizeof(netbnum));
+		memcpy((buf + sizeof(netopcode) + sizeof(netbnum)), data, datalen);
+	}
+	return buf;
+}
+
+nbd_tftp_packet_ack nbd_tftp_de_ack(char *buf, ssize_t buflen) {
+	nbd_tftp_packet_ack ack = { 0, 0 };
+	if ((buf != NULL) && (buflen == 4)) {
+		uint16_t opcode = ((uint16_t)buf[0] << 8) + buf[1];
+		uint16_t block_num = ((uint16_t)buf[2] << 8) + buf[3];
+		ack.opcode = opcode;
+		ack.block_num = block_num;
+	}
+	return ack;
+}
+