diff --git a/src/libsam3/libsam3.c b/src/libsam3/libsam3.c index ab0cd3e..f52e1ee 100644 --- a/src/libsam3/libsam3.c +++ b/src/libsam3/libsam3.c @@ -1,34 +1,17 @@ -/* - * Copyright © 2023 I2P - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the “Software”), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. +/* This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. * - * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://git.idk.i2p/i2p-hackers/libsam3/ - */ - + * I2P-Bote: + * 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV + * we are the Borg. */ #include "libsam3.h" #include #include #include -#include #include #include #include @@ -38,8 +21,8 @@ #ifdef __MINGW32__ //#include -#include #include +#include #include #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 @@ -47,31 +30,21 @@ #ifndef SHUT_RDWR #define SHUT_RDWR 2 #endif +#define close closesocket #endif #if defined(__unix__) || defined(__APPLE__) #include #include #include +#include #include #include -#include -#endif -#if defined(__unix__) && !defined(__APPLE__) +#ifndef __APPLE__ #include #endif -#if defined(__APPLE__) -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 -#endif -#include -uint32_t TickCount() { - uint64_t mat = mach_absolute_time(); - uint32_t mul = 0x80d9594e; - return ((((0xffffffff & mat) * mul) >> 32) + (mat >> 32) * mul) >> 23; -} #endif //////////////////////////////////////////////////////////////////////////////// @@ -96,8 +69,14 @@ int sam3tcpSetTimeoutSend(int fd, int timeoutms) { struct timeval tv; // ms2timeval(&tv, timeoutms); - return (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0 ? -1 +#ifdef _WIN32 + DWORD timeout = timeoutms; + return (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)) < 0 ? -1 : 0); +#else + return (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv)) < 0 ? -1 + : 0); +#endif } return -1; } @@ -107,8 +86,14 @@ int sam3tcpSetTimeoutReceive(int fd, int timeoutms) { struct timeval tv; // ms2timeval(&tv, timeoutms); - return (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ? -1 +#ifdef _WIN32 + DWORD timeout = timeoutms; + return (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) < 0 ? -1 : 0); +#else + return (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) < 0 ? -1 + : 0); +#endif } return -1; } @@ -148,7 +133,7 @@ int sam3tcpConnectIP(uint32_t ip, int port) { } } // - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&val, sizeof(val)); // if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { if (libsam3_debug) @@ -555,7 +540,7 @@ SAMFieldList *sam3ParseReply(const char *rep) { // first item is always 2-word reply, with first word in name and second in // value SAMFieldList *sam3ReadReply(int fd) { - char rep[2048]; // should be enough for any reply + char rep[8192]; // should be enough for any reply // if (sam3tcpReceiveStr(fd, rep, sizeof(rep)) < 0) return NULL; @@ -643,27 +628,22 @@ static inline uint32_t hashint(uint32_t a) { } static uint32_t genSeed(void) { - volatile uint32_t seed = 1; uint32_t res; -#ifndef WIN32 - #ifndef __APPLE__ - struct sysinfo sy; - pid_t pid = getpid(); - // - sysinfo(&sy); - res = hashint((uint32_t)pid) ^ hashint((uint32_t)time(NULL)) ^ - hashint((uint32_t)sy.sharedram) ^ hashint((uint32_t)sy.bufferram) ^ - hashint((uint32_t)sy.uptime); - #else - res = hashint((uint32_t)getpid()) ^ - hashint((uint32_t)TickCount()); - #endif -#else +#if defined(__linux__) + struct sysinfo sy; + pid_t pid = getpid(); + sysinfo(&sy); + res = hashint((uint32_t)pid) ^ hashint((uint32_t)time(NULL)) ^ + hashint((uint32_t)sy.sharedram) ^ hashint((uint32_t)sy.bufferram) ^ + hashint((uint32_t)sy.uptime); +#elif defined(WIN32) res = hashint((uint32_t)GetCurrentProcessId()) ^ hashint((uint32_t)GetTickCount()); +#else + res = hashint((uint32_t)getpid()) ^ hashint((uint32_t)time(NULL)); #endif - res += __sync_fetch_and_add(&seed, 1); - // + + // Return hashint(res) if that's what the original code did return hashint(res); } @@ -758,23 +738,29 @@ int sam3GenerateKeys(Sam3Session *ses, const char *hostname, int port, return -1; } // - if (sam3tcpPrintf(fd, "DEST GENERATE %s\n", sigtypes[(int)sigType]) < 0) { + if (sam3tcpPrintf(fd, "DEST GENERATE %s\n", sigtypes[sigType]) >= 0) { + if ((rep = sam3ReadReply(fd)) != NULL && + sam3IsGoodReply(rep, "DEST", "REPLY", NULL, NULL)) { + const char *pub = sam3FindField(rep, "PUB"), + *priv = sam3FindField(rep, "PRIV"); + // + if (pub != NULL && sam3CheckValidKeyLength(pub) && priv != NULL && + strlen(priv) >= SAM3_PRIVKEY_MIN_SIZE) { + strncpy(ses->pubkey, pub, sizeof(ses->pubkey) - 1); + ses->pubkey[sizeof(ses->pubkey) - 1] = 0; + strncpy(ses->privkey, priv, sizeof(ses->privkey) - 1); + ses->privkey[sizeof(ses->privkey) - 1] = 0; + res = 0; + } else { + if (pub == NULL || !sam3CheckValidKeyLength(pub)) strcpyerr(ses, "PUBKEY_ERROR"); + else strcpyerr(ses, "PRIVKEY_ERROR"); + } + } else { + strcpyerr(ses, "DEST_ERROR"); + } + } else { strcpyerr(ses, "DEST_ERROR"); } - - rep = sam3ReadReply(fd); - // sam3DumpFieldList(rep); - if (!sam3IsGoodReply(rep, "DEST", "REPLY", "PUB", NULL)) { - strcpyerr(ses, "PUBKEY_ERROR"); - } - if (!sam3IsGoodReply(rep, "DEST", "REPLY", "PRIV", NULL)) { - strcpyerr(ses, "PRIVKEY_ERROR"); - } - const char *pub = sam3FindField(rep, "PUB"); - strcpy(ses->pubkey, pub); - const char *priv = sam3FindField(rep, "PRIV"); - strcpy(ses->privkey, priv); - res = 0; // sam3FreeFieldList(rep); sam3tcpDisconnect(fd); @@ -804,7 +790,8 @@ int sam3NameLookup(Sam3Session *ses, const char *hostname, int port, // if (strcmp(rs, "OK") == 0) { if (pub != NULL && sam3CheckValidKeyLength(pub)) { - strcpy(ses->destkey, pub); + strncpy(ses->destkey, pub, sizeof(ses->destkey) - 1); + ses->destkey[sizeof(ses->destkey) - 1] = 0; strcpyerr(ses, NULL); res = 0; } @@ -931,7 +918,7 @@ int sam3CreateSession(Sam3Session *ses, const char *hostname, int port, strlen(v) < SAM3_PRIVKEY_MIN_SIZE) { if (libsam3_debug) fprintf(stderr, "sam3CreateSession: invalid reply (%ld)...\n", - (v != NULL ? strlen(v) : -1)); + (long)(v != NULL ? strlen(v) : -1)); if (libsam3_debug) sam3DumpFieldList(rep); sam3FreeFieldList(rep); @@ -939,10 +926,11 @@ int sam3CreateSession(Sam3Session *ses, const char *hostname, int port, } // save our keys if (strlen(v) > SAM3_PRIVKEY_MAX_SIZE) { - fprintf(stderr, "ERROR, Unexpected key size (%li)!\n", strlen(v)); + fprintf(stderr, "ERROR, Unexpected key size (%li)!\n", (long)strlen(v)); goto error; } - strcpy(ses->privkey, v); + strncpy(ses->privkey, v, sizeof(ses->privkey) - 1); + ses->privkey[sizeof(ses->privkey) - 1] = 0; sam3FreeFieldList(rep); // get public key if (sam3tcpPrintf(ses->fd, "NAMING LOOKUP NAME=ME\n") < 0) @@ -955,13 +943,14 @@ int sam3CreateSession(Sam3Session *ses, const char *hostname, int port, !sam3CheckValidKeyLength(v)) { if (libsam3_debug) fprintf(stderr, "sam3CreateSession: invalid NAMING reply (%ld)...\n", - (v != NULL ? strlen(v) : -1)); + (long)(v != NULL ? strlen(v) : -1)); if (libsam3_debug) sam3DumpFieldList(rep); sam3FreeFieldList(rep); goto error; } - strcpy(ses->pubkey, v); + strncpy(ses->pubkey, v, sizeof(ses->pubkey) - 1); + ses->pubkey[sizeof(ses->pubkey) - 1] = 0; sam3FreeFieldList(rep); // if (libsam3_debug) @@ -978,12 +967,6 @@ Sam3Connection *sam3StreamConnect(Sam3Session *ses, const char *destkey) { SAMFieldList *rep; Sam3Connection *conn; // - for (size_t i = 0; destkey[i] != 0; i++){ - if (destkey[i] == '\n'){ - strcpyerr(ses, "INVALID_KEY_SYMBOLS"); - return NULL; - } - } if (ses->type != SAM3_SESSION_STREAM) { strcpyerr(ses, "INVALID_SESSION_TYPE"); return NULL; @@ -1029,7 +1012,8 @@ Sam3Connection *sam3StreamConnect(Sam3Session *ses, const char *destkey) { } sam3FreeFieldList(rep); if (conn != NULL) { - strcpy(conn->destkey, destkey); + strncpy(conn->destkey, destkey, sizeof(conn->destkey) - 1); + conn->destkey[sizeof(conn->destkey) - 1] = 0; conn->ses = ses; conn->next = ses->connlist; ses->connlist = conn; @@ -1046,7 +1030,7 @@ Sam3Connection *sam3StreamConnect(Sam3Session *ses, const char *destkey) { Sam3Connection *sam3StreamAccept(Sam3Session *ses) { if (ses != NULL) { SAMFieldList *rep = NULL; - char repstr[1024]; + char repstr[8192]; Sam3Connection *conn; // if (ses->type != SAM3_SESSION_STREAM) { @@ -1097,7 +1081,8 @@ Sam3Connection *sam3StreamAccept(Sam3Session *ses) { goto error; } sam3FreeFieldList(rep); - strcpy(conn->destkey, repstr); + strncpy(conn->destkey, repstr, sizeof(conn->destkey) - 1); + conn->destkey[sizeof(conn->destkey) - 1] = 0; conn->ses = ses; conn->next = ses->connlist; ses->connlist = conn; @@ -1190,12 +1175,11 @@ int sam3DatagramSend(Sam3Session *ses, const char *destkey, const void *buf, strcpyerr(ses, "INVALID_DATA"); return -1; } - dbufsz = bufsize + 4 + strlen(destkey) + 1 + strlen(ses->channel) + 1; + dbufsz = bufsize + 4 + SAM3_PUBKEY_SIZE + 1 + strlen(ses->channel) + 1; if ((dbuf = malloc(dbufsz)) == NULL) { strcpyerr(ses, "OUT_OF_MEMORY"); return -1; } - memset(dbuf, 0, dbufsz); sprintf(dbuf, "3.0 %s %s\n", ses->channel, destkey); memcpy(dbuf + strlen(dbuf), buf, bufsize); res = sam3udpSendToIP(ses->ip, ses->port, dbuf, dbufsz); @@ -1235,8 +1219,10 @@ ssize_t sam3DatagramReceive(Sam3Session *ses, void *buf, size_t bufsize) { } // if ((v = sam3FindField(rep, "DESTINATION")) != NULL && - sam3CheckValidKeyLength(v)) - strncpy(ses->destkey, v, sizeof(ses->destkey)); + sam3CheckValidKeyLength(v)) { + strncpy(ses->destkey, v, sizeof(ses->destkey) - 1); + ses->destkey[sizeof(ses->destkey) - 1] = 0; + } v = sam3FindField(rep, "SIZE"); // we have this field -- for sure if (!v[0] || !isdigit(*v)) { strcpyerr(ses, "I2P_ERROR_SIZE"); diff --git a/src/libsam3/libsam3.h b/src/libsam3/libsam3.h index 316e122..afcd809 100644 --- a/src/libsam3/libsam3.h +++ b/src/libsam3/libsam3.h @@ -1,34 +1,22 @@ -/* - * Copyright © 2023 I2P - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the “Software”), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/* This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. * - * http://git.idk.i2p/i2p-hackers/libsam3/ - */ + * I2P-Bote: + * 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV + * we are the Borg. */ #ifndef LIBSAM3_H #define LIBSAM3_H +#include +#include +#include + #include #include #include -#include #ifndef _SSIZE_T_DEFINED #define _SSIZE_T_DEFINED @@ -53,9 +41,9 @@ extern int libsam3_debug; #define SAM3_DESTINATION_TRANSIENT (NULL) #define SAM3_PUBKEY_SIZE (516) -#define SAM3_CERT_SIZE (100) -#define SAM3_PRIVKEY_MIN_SIZE (884) -#define SAM3_PRIVKEY_MAX_SIZE (1024) +#define SAM3_CERT_SIZE (3580) +#define SAM3_PRIVKEY_MIN_SIZE (256) +#define SAM3_PRIVKEY_MAX_SIZE (8192) //////////////////////////////////////////////////////////////////////////////// /* returns fd or -1 */ @@ -153,14 +141,14 @@ typedef struct Sam3Session { Sam3SessionType type; Sam3SigType sigType; int fd; - char privkey[SAM3_PRIVKEY_MAX_SIZE + 1]; // destination private key (asciiz) + char privkey[SAM3_PRIVKEY_MIN_SIZE + 1]; // destination private key (asciiz) char pubkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE + 1]; // destination public key (asciiz) char channel[66]; // name of this sam session (asciiz) char destkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE + 1]; // for DGRAM sessions (asciiz) // int destsig; - char error[32]; // error message (asciiz) + char error[256]; // error message (asciiz) uint32_t ip; int port; // this will be changed to UDP port for DRAM/RAW (can be 0) struct Sam3Connection *connlist; // list of opened connections @@ -175,7 +163,7 @@ typedef struct Sam3Connection { char destkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE + 1]; // remote destination public key (asciiz) int destcert; - char error[32]; // error message (asciiz) + char error[256]; // error message (asciiz) } Sam3Connection; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libsam3a/libsam3a.c b/src/libsam3a/libsam3a.c index 3811489..624879f 100644 --- a/src/libsam3a/libsam3a.c +++ b/src/libsam3a/libsam3a.c @@ -1,28 +1,14 @@ -/* - * Copyright © 2023 I2P - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the “Software”), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. +/* async SAMv3 library * - * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. * - * http://git.idk.i2p/i2p-hackers/libsam3/ - */ - + * I2P-Bote: + * 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV + * we are the Borg. */ #include "libsam3a.h" #include @@ -35,10 +21,12 @@ #include #include +#include + #ifdef __MINGW32__ //#include -#include #include +#include #include #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 @@ -46,10 +34,8 @@ #ifndef SHUT_RDWR #define SHUT_RDWR 2 #endif -#endif - -#if defined(__unix__) && !defined(__APPLE__) -#include +#define close closesocket +#define ioctl ioctlsocket #endif #if defined(__unix__) || defined(__APPLE__) @@ -59,26 +45,11 @@ #include #include #include -#endif -#if defined(__APPLE__) -#include -#include -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 0 -#endif -#ifndef SOCK_NONBLOCK -#include -#define SOCK_NONBLOCK O_NONBLOCK -#endif -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 +#ifndef __APPLE__ +#include #endif -uint32_t TickCount() { - uint64_t mat = mach_absolute_time(); - uint32_t mul = 0x80d9594e; - return ((((0xffffffff & mat) * mul) >> 32) + (mat >> 32) * mul) >> 23; -} + #endif //////////////////////////////////////////////////////////////////////////////// @@ -88,11 +59,11 @@ int libsam3a_debug = 0; #define DEFAULT_UDP_PORT (7655) //////////////////////////////////////////////////////////////////////////////// -extern uint64_t sam3atimeval2ms(const struct timeval *tv) { +uint64_t sam3atimeval2ms(const struct timeval *tv) { return ((uint64_t)tv->tv_sec) * 1000 + ((uint64_t)tv->tv_usec) / 1000; } -extern void sam3ams2timeval(struct timeval *tv, uint64_t ms) { +void sam3ams2timeval(struct timeval *tv, uint64_t ms) { tv->tv_sec = ms / 1000; tv->tv_usec = (ms % 1000) * 1000; } @@ -104,8 +75,8 @@ static inline int isValidKeyChar(char ch) { } int sam3aIsValidPubKey(const char *key) { - if (key != NULL && strlen(key) == SAM3A_PUBKEY_SIZE) { - for (int f = 0; f < SAM3A_PUBKEY_SIZE; ++f) + if (key != NULL && strlen(key) >= SAM3A_PUBKEY_SIZE) { + for (int f = 0; f < (int)strlen(key); ++f) if (!isValidKeyChar(key[f])) return 0; return 1; @@ -114,8 +85,8 @@ int sam3aIsValidPubKey(const char *key) { } int sam3aIsValidPrivKey(const char *key) { - if (key != NULL && strlen(key) == SAM3A_PRIVKEY_SIZE) { - for (int f = 0; f < SAM3A_PRIVKEY_SIZE; ++f) + if (key != NULL && strlen(key) >= SAM3A_PRIVKEY_SIZE) { + for (int f = 0; f < (int)strlen(key); ++f) if (!isValidKeyChar(key[f])) return 0; return 1; @@ -150,11 +121,15 @@ static int sam3aSocketSetTimeoutReceive (int fd, int timeoutms) { */ static int sam3aBytesAvail(int fd) { +#ifdef _WIN32 + u_long av = 0; +#else int av = 0; +#endif // if (ioctl(fd, FIONREAD, &av) < 0) return -1; - return av; + return (int)av; } static uint32_t sam3aResolveHost(const char *hostname) { @@ -179,11 +154,28 @@ static int sam3aConnect(uint32_t ip, int port, int *complete) { if (ip == 0 || ip == 0xffffffffUL || port < 1 || port > 65535) return -1; // - // yes, this is Linux-specific; you know what? i don't care. - if ((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)) < 0) - return -1; + // For Linux, use the original flags. + // For macOS (and other BSDs), use standard socket and then set non-blocking. + #if defined(__linux__) + if ((fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)) < 0) + #else + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + #endif + return -1; + + #if defined(_WIN32) || defined(__MINGW32__) + // On Windows, use ioctlsocket (aliased to ioctl above) to set non-blocking + u_long mode = 1; + ioctl(fd, FIONBIO, &mode); + #elif !defined(__linux__) + // On macOS/BSD, set non-blocking after creation using fcntl + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + // Note: SOCK_CLOEXEC is not strictly necessary for basic functionality + // on macOS as it is for security, but usually handled differently. + #endif // - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&val, sizeof(val)); // for (;;) { struct sockaddr_in addr; @@ -688,25 +680,24 @@ static inline uint32_t hashint(uint32_t a) { static uint32_t genSeed(void) { volatile uint32_t seed = 1; uint32_t res; -#ifndef WIN32 - #ifndef __APPLE__ - struct sysinfo sy; - pid_t pid = getpid(); - // - sysinfo(&sy); - res = hashint((uint32_t)pid) ^ hashint((uint32_t)time(NULL)) ^ - hashint((uint32_t)sy.sharedram) ^ hashint((uint32_t)sy.bufferram) ^ - hashint((uint32_t)sy.uptime); - #else - res = hashint((uint32_t)getpid()) ^ - hashint((uint32_t)TickCount()); - #endif -#else + +#if defined(__linux__) + struct sysinfo sy; + pid_t pid = getpid(); + sysinfo(&sy); + res = hashint((uint32_t)pid) ^ hashint((uint32_t)time(NULL)) ^ + hashint((uint32_t)sy.sharedram) ^ hashint((uint32_t)sy.bufferram) ^ + hashint((uint32_t)sy.uptime); +#elif defined(WIN32) res = hashint((uint32_t)GetCurrentProcessId()) ^ hashint((uint32_t)GetTickCount()); +#else + // Fallback for macOS/BSD: use PID, time, and address of the stack variable + // to ensure some entropy even without sysinfo + res = hashint((uint32_t)getpid()) ^ hashint((uint32_t)time(NULL)) ^ hashint((uintptr_t)&seed); #endif + res += __sync_fetch_and_add(&seed, 1); - // return hashint(res); } @@ -894,18 +885,18 @@ static void aioSesCmdSender(Sam3ASession *ses) { // if (ses->aio.dataPos == ses->aio.dataUsed) { // hello sent, now wait for reply - // 2048 bytes of reply line should be enough - if (ses->aio.dataSize < 2049) { - char *n = realloc(ses->aio.data, 2049); + // 8192 bytes of reply line should be enough + if (ses->aio.dataSize < 8193) { + char *n = realloc(ses->aio.data, 8193); // if (n == NULL) { sesError(ses, "MEMORY_ERROR"); return; } ses->aio.data = n; - ses->aio.dataSize = 2049; + ses->aio.dataSize = 8193; } - ses->aio.dataUsed = 2048; + ses->aio.dataUsed = 8192; ses->aio.dataPos = 0; ses->cbAIOProcessorR = aioSesCmdReplyReader; ses->cbAIOProcessorW = NULL; @@ -980,7 +971,7 @@ static void aioSesNameMeChecker(Sam3ASession *ses) { } if (!sam3aIsGoodReply(rep, "NAMING", "REPLY", "RESULT", "OK") || (v = sam3aFindField(rep, "VALUE")) == NULL || - strlen(v) != SAM3A_PUBKEY_SIZE) { + strlen(v) < SAM3A_PUBKEY_SIZE) { // if (libsam3a_debug) fprintf(stderr, "sam3aCreateSession: invalid NAMING // reply (%d)...\n", (v != NULL ? strlen(v) : -1)); if ((v = sam3aFindField(rep, "RESULT")) != NULL && strcmp(v, "OK") == 0) @@ -989,7 +980,8 @@ static void aioSesNameMeChecker(Sam3ASession *ses) { sam3aFreeFieldList(rep); return; } - strcpy(ses->pubkey, v); + strncpy(ses->pubkey, v, sizeof(ses->pubkey) - 1); + ses->pubkey[sizeof(ses->pubkey) - 1] = 0; sam3aFreeFieldList(rep); // ses->cbAIOProcessorR = ses->cbAIOProcessorW = NULL; @@ -1008,7 +1000,7 @@ static void aioSesCreateChecker(Sam3ASession *ses) { } if (!sam3aIsGoodReply(rep, "SESSION", "STATUS", "RESULT", "OK") || (v = sam3aFindField(rep, "DESTINATION")) == NULL || - strlen(v) != SAM3A_PRIVKEY_SIZE) { + strlen(v) < SAM3A_PRIVKEY_SIZE) { sam3aFreeFieldList(rep); if ((v = sam3aFindField(rep, "RESULT")) != NULL && strcmp(v, "OK") == 0) v = NULL; @@ -1017,7 +1009,8 @@ static void aioSesCreateChecker(Sam3ASession *ses) { } // ok // fprintf(stderr, "\nPK: %s\n", v); - strcpy(ses->privkey, v); + strncpy(ses->privkey, v, sizeof(ses->privkey) - 1); + ses->privkey[sizeof(ses->privkey) - 1] = 0; sam3aFreeFieldList(rep); // get our public key if (aioSesSendCmdWaitReply(ses, aioSesNameMeChecker, "%s\n", @@ -1044,7 +1037,7 @@ static void aioSesConnected(Sam3ASession *ses) { int res; socklen_t len = sizeof(res); // - if (getsockopt(ses->fd, SOL_SOCKET, SO_ERROR, &res, &len) == 0 && res == 0) { + if (getsockopt(ses->fd, SOL_SOCKET, SO_ERROR, (char*)&res, &len) == 0 && res == 0) { // ok, connected if (sam3aSesStartHandshake(ses, NULL) < 0) sesError(ses, NULL); @@ -1076,7 +1069,8 @@ int sam3aCreateSessionEx(Sam3ASession *ses, const Sam3ASessionCallbacks *cb, goto error; if (privkey == NULL) privkey = "TRANSIENT"; - strcpy(ses->privkey, privkey); + strncpy(ses->privkey, privkey, sizeof(ses->privkey) - 1); + ses->privkey[sizeof(ses->privkey) - 1] = 0; if (params != NULL && (ses->params = strdup(params)) == NULL) goto error; ses->timeoutms = timeoutms; @@ -1151,10 +1145,12 @@ static void aioSesKeyGenChecker(Sam3ASession *ses) { const char *pub = sam3aFindField(rep, "PUB"), *priv = sam3aFindField(rep, "PRIV"); // - if (pub != NULL && strlen(pub) == SAM3A_PUBKEY_SIZE && priv != NULL && - strlen(priv) == SAM3A_PRIVKEY_SIZE) { - strcpy(ses->pubkey, pub); - strcpy(ses->privkey, priv); + if (pub != NULL && strlen(pub) >= SAM3A_PUBKEY_SIZE && priv != NULL && + strlen(priv) >= SAM3A_PRIVKEY_SIZE) { + strncpy(ses->pubkey, pub, sizeof(ses->pubkey) - 1); + ses->pubkey[sizeof(ses->pubkey) - 1] = 0; + strncpy(ses->privkey, priv, sizeof(ses->privkey) - 1); + ses->privkey[sizeof(ses->privkey) - 1] = 0; sam3aFreeFieldList(rep); if (ses->cb.cbCreated != NULL) ses->cb.cbCreated(ses); @@ -1223,8 +1219,9 @@ static void aioSesNameResChecker(Sam3ASession *ses) { *pub = sam3aFindField(rep, "VALUE"); // if (strcmp(rs, "OK") == 0) { - if (pub != NULL && strlen(pub) == SAM3A_PUBKEY_SIZE) { - strcpy(ses->destkey, pub); + if (pub != NULL && strlen(pub) >= SAM3A_PUBKEY_SIZE) { + strncpy(ses->destkey, pub, sizeof(ses->destkey) - 1); + ses->destkey[sizeof(ses->destkey) - 1] = 0; sam3aFreeFieldList(rep); if (ses->cb.cbCreated != NULL) ses->cb.cbCreated(ses); @@ -1318,18 +1315,18 @@ static void aioConnCmdSender(Sam3AConnection *conn) { // if (conn->aio.dataPos == conn->aio.dataUsed) { // hello sent, now wait for reply - // 2048 bytes of reply line should be enough - if (conn->aio.dataSize < 2049) { - char *n = realloc(conn->aio.data, 2049); + // 8192 bytes of reply line should be enough + if (conn->aio.dataSize < 8193) { + char *n = realloc(conn->aio.data, 8193); // if (n == NULL) { connError(conn, "MEMORY_ERROR"); return; } conn->aio.data = n; - conn->aio.dataSize = 2049; + conn->aio.dataSize = 8193; } - conn->aio.dataUsed = 2048; + conn->aio.dataUsed = 8192; conn->aio.dataPos = 0; conn->cbAIOProcessorR = aioConnCmdReplyReader; conn->cbAIOProcessorW = NULL; @@ -1500,7 +1497,7 @@ static void aioConnConnected(Sam3AConnection *conn) { int res; socklen_t len = sizeof(res); // - if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &res, &len) == 0 && res == 0) { + if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (char*)&res, &len) == 0 && res == 0) { // ok, connected if (sam3aConnStartHandshake(conn, NULL) < 0) connError(conn, NULL); @@ -1552,14 +1549,15 @@ Sam3AConnection *sam3aStreamConnectEx(Sam3ASession *ses, const Sam3AConnectionCallbacks *cb, const char *destkey, int timeoutms) { if (sam3aIsActiveSession(ses) && ses->type == SAM3A_SESSION_STREAM && - destkey != NULL && strlen(destkey) == SAM3A_PUBKEY_SIZE) { + destkey != NULL && strlen(destkey) >= SAM3A_PUBKEY_SIZE) { Sam3AConnection *conn = calloc(1, sizeof(Sam3AConnection)); // if (conn == NULL) return NULL; if (cb != NULL) conn->cb = *cb; - strcpy(conn->destkey, destkey); + strncpy(conn->destkey, destkey, sizeof(conn->destkey) - 1); + conn->destkey[sizeof(conn->destkey) - 1] = 0; conn->timeoutms = timeoutms; // conn->aio.udata = aioConConnectHandshacked; @@ -1584,14 +1582,15 @@ Sam3AConnection *sam3aStreamConnectEx(Sam3ASession *ses, static void aioConnAcceptCheckerA(Sam3AConnection *conn) { SAMFieldList *rep = sam3aParseReply(conn->aio.data); // - if (rep != NULL || strlen(conn->aio.data) != SAM3A_PUBKEY_SIZE || + if (rep != NULL || strlen(conn->aio.data) < SAM3A_PUBKEY_SIZE || !sam3aIsValidPubKey(conn->aio.data)) { sam3aFreeFieldList(rep); connError(conn, NULL); return; } sam3aFreeFieldList(rep); - strcpy(conn->destkey, conn->aio.data); + strncpy(conn->destkey, conn->aio.data, sizeof(conn->destkey) - 1); + conn->destkey[sizeof(conn->destkey) - 1] = 0; conn->callDisconnectCB = 1; conn->cbAIOProcessorR = aioConnDataReader; conn->cbAIOProcessorW = aioConnDataWriter; diff --git a/src/libsam3a/libsam3a.h b/src/libsam3a/libsam3a.h index 85f2d9b..f5bba65 100644 --- a/src/libsam3a/libsam3a.h +++ b/src/libsam3a/libsam3a.h @@ -1,42 +1,28 @@ -/* - * Copyright © 2023 I2P - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the “Software”), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. +/* async SAMv3 library * - * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. * - * http://git.idk.i2p/i2p-hackers/libsam3/ - */ - + * I2P-Bote: + * 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV + * we are the Borg. */ #ifndef LIBSAM3A_H #define LIBSAM3A_H +#include #include #include #include #include -#include #ifdef __MINGW32__ //#include -#include #include +#include #include //#define SOCK_CLOEXEC O_CLOEXEC //#define SOCK_NONBLOCK O_NONBLOCK @@ -64,7 +50,9 @@ extern int libsam3a_debug; #define SAM3A_DESTINATION_TRANSIENT (NULL) #define SAM3A_PUBKEY_SIZE (516) -#define SAM3A_PRIVKEY_SIZE (884) +#define SAM3A_CERT_SIZE (3580) +#define SAM3A_PRIVKEY_SIZE (1024) +#define SAM3A_PRIVKEY_MAX_SIZE (8192) //////////////////////////////////////////////////////////////////////////////// extern uint64_t sam3atimeval2ms(const struct timeval *tv); @@ -114,11 +102,11 @@ struct Sam3ASession { Sam3ASessionType type; /** session type */ int fd; /** socket file descriptor */ int cancelled; /** fd was shutdown()ed, but not closed yet */ - char privkey[SAM3A_PRIVKEY_SIZE + 1]; /** private key (asciiz) */ - char pubkey[SAM3A_PUBKEY_SIZE + 1]; /** public key (asciiz) */ + char privkey[SAM3A_PRIVKEY_MAX_SIZE + 1]; /** private key (asciiz) */ + char pubkey[SAM3A_PUBKEY_SIZE + SAM3A_CERT_SIZE + 1]; /** public key (asciiz) */ char channel[66]; /** channel name (asciiz) */ - char destkey[SAM3A_PUBKEY_SIZE + 1]; /** for DGRAM sessions (asciiz) */ - char error[64]; /** error message (asciiz) */ + char destkey[SAM3A_PUBKEY_SIZE + SAM3A_CERT_SIZE + 1]; /** for DGRAM sessions (asciiz) */ + char error[256]; /** error message (asciiz) */ uint32_t ip; /** ipv4 address of sam api interface */ int port; /** UDP port for DRAM/RAW (can be 0) */ Sam3AConnection *connlist; /** list of opened connections */ @@ -166,8 +154,8 @@ struct Sam3AConnection { /** file descriptor */ int fd; int cancelled; // fd was shutdown()ed, but not closed yet - char destkey[SAM3A_PUBKEY_SIZE + 1]; // (asciiz) - char error[32]; // (asciiz) + char destkey[SAM3A_PUBKEY_SIZE + SAM3A_CERT_SIZE + 1]; // (asciiz) + char error[256]; // (asciiz) /** begin internal members */ // for async i/o