client_network.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. // Client network command handlers for HaxServ
  2. //
  3. // Written by: Test_User <hax@andrewyu.org>
  4. //
  5. // This is free and unencumbered software released into the public
  6. // domain.
  7. //
  8. // Anyone is free to copy, modify, publish, use, compile, sell, or
  9. // distribute this software, either in source code form or as a compiled
  10. // binary, for any purpose, commercial or non-commercial, and by any
  11. // means.
  12. //
  13. // In jurisdictions that recognize copyright laws, the author or authors
  14. // of this software dedicate any and all copyright interest in the
  15. // software to the public domain. We make this dedication for the benefit
  16. // of the public at large and to the detriment of our heirs and
  17. // successors. We intend this dedication to be an overt act of
  18. // relinquishment in perpetuity of all present and future rights to this
  19. // software under copyright law.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  24. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  25. // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  26. // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  27. // OTHER DEALINGS IN THE SOFTWARE.
  28. #include <gnutls/gnutls.h>
  29. #include <netdb.h>
  30. #include <arpa/inet.h>
  31. #include <sys/types.h>
  32. #include <netinet/in.h>
  33. #include <sys/socket.h>
  34. #include <string.h>
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include "commands.h"
  38. #include "network.h"
  39. #include "config.h"
  40. #include "types.h"
  41. #include "table.h"
  42. #include "tls.h"
  43. struct table client_network_commands = {0};
  44. struct string client_nick = {0};
  45. uint8_t client_connected;
  46. int add_local_client(struct string uid, struct string nick_arg, struct string vhost_arg, struct string ident_arg, struct string realname_arg, time_t timestamp, char fake_cert) {
  47. if (has_table_index(user_list, uid))
  48. return 1;
  49. struct user_info *user = malloc(sizeof(*user));
  50. if (!user)
  51. goto add_local_client_fail_user;
  52. struct string server = {
  53. .data = malloc(3),
  54. .len = 3,
  55. };
  56. if (!server.data)
  57. goto add_local_client_fail_server;
  58. memcpy(server.data, "1HC", 3);
  59. struct string hostname = {
  60. .data = malloc(vhost_arg.len),
  61. .len = vhost_arg.len,
  62. };
  63. if (!hostname.data)
  64. goto add_local_client_fail_hostname;
  65. memcpy(hostname.data, vhost_arg.data, hostname.len);
  66. struct string vhost = {
  67. .data = malloc(vhost_arg.len),
  68. .len = vhost_arg.len,
  69. };
  70. if (!vhost.data)
  71. goto add_local_client_fail_vhost;
  72. memcpy(vhost.data, vhost_arg.data, vhost.len);
  73. struct string ident = {
  74. .data = malloc(ident_arg.len),
  75. .len = ident_arg.len,
  76. };
  77. if (!ident.data)
  78. goto add_local_client_fail_ident;
  79. memcpy(ident.data, ident_arg.data, ident.len);
  80. struct string ip = {
  81. .data = malloc(9),
  82. .len = 9,
  83. };
  84. if (!ip.data)
  85. goto add_local_client_fail_ip;
  86. memcpy(ip.data, "/dev/null", 9);
  87. struct string realname = {
  88. .data = malloc(realname_arg.len),
  89. .len = realname_arg.len,
  90. };
  91. if (!realname.data)
  92. goto add_local_client_fail_realname;
  93. memcpy(realname.data, realname_arg.data, realname.len);
  94. struct string nick = {
  95. .data = malloc(nick_arg.len),
  96. .len = nick_arg.len,
  97. };
  98. if (!nick.data)
  99. goto add_local_client_fail_nick;
  100. memcpy(nick.data, nick_arg.data, nick.len);
  101. *user = (struct user_info){
  102. .nick_ts = (uint64_t)timestamp,
  103. .user_ts = (uint64_t)timestamp,
  104. .server = server,
  105. .nick = nick,
  106. .hostname = hostname,
  107. .vhost = vhost,
  108. .ident = ident,
  109. .ip = ip,
  110. .realname = realname,
  111. .opertype = {.data = malloc(0), .len = 0},
  112. .metadata = {.array = malloc(0), .len = 0},
  113. };
  114. set_table_index(&user_list, uid, user);
  115. SEND(STRING("GLOADMODULE m_servprotect\n")); // required for the +k we're about to use
  116. char string_time[21];
  117. snprintf(string_time, 21, "%ld", timestamp);
  118. SEND(STRING("UID "));
  119. SEND(uid);
  120. SEND(STRING(" "));
  121. SEND(NULSTR(string_time));
  122. SEND(STRING(" "));
  123. SEND(nick);
  124. SEND(STRING(" "));
  125. SEND(vhost);
  126. SEND(STRING(" "));
  127. SEND(vhost);
  128. SEND(STRING(" "));
  129. SEND(ident);
  130. SEND(STRING(" "));
  131. SEND(ip);
  132. SEND(STRING(" "));
  133. SEND(NULSTR(string_time));
  134. SEND(STRING(" +k :"));
  135. SEND(realname);
  136. SEND(STRING("\n"));
  137. if (fake_cert) {
  138. SEND(STRING(":1HC METADATA "));
  139. SEND(uid);
  140. SEND(STRING(" ssl_cert :vTrse "));
  141. SEND(client_cert);
  142. SEND(STRING("\n"));
  143. }
  144. if (!STRING_EQ(uid, STRING("1HC000000"))) { // Don't oper haxserv, because echo is unprivileged
  145. SEND(STRING(":"));
  146. SEND(uid);
  147. SEND(STRING(" OPERTYPE "));
  148. SEND(opertype);
  149. SEND(STRING("\n"));
  150. }
  151. return 0;
  152. add_local_client_fail_nick:
  153. free(realname.data);
  154. add_local_client_fail_realname:
  155. free(ip.data);
  156. add_local_client_fail_ip:
  157. free(ident.data);
  158. add_local_client_fail_ident:
  159. free(vhost.data);
  160. add_local_client_fail_vhost:
  161. free(hostname.data);
  162. add_local_client_fail_hostname:
  163. free(server.data);
  164. add_local_client_fail_server:
  165. free(user);
  166. add_local_client_fail_user:
  167. WRITES(2, STRING("OOM! (add_local_client)\n"));
  168. return 1;
  169. }
  170. int client_nick_handler(uint64_t argc, struct string *argv) {
  171. if (argc < 1)
  172. return 1;
  173. void *tmp = malloc(argv[0].len);
  174. if (!tmp)
  175. return 1;
  176. void *name_for_tables;
  177. if (client_connected) {
  178. name_for_tables = malloc(argv[0].len);
  179. if (!name_for_tables) {
  180. free(tmp);
  181. return 1;
  182. }
  183. memcpy(name_for_tables, argv[0].data, argv[0].len);
  184. }
  185. memcpy(tmp, argv[0].data, argv[0].len);
  186. if (client_connected) {
  187. SENDCLIENT(STRING(":"));
  188. SENDCLIENT(client_nick);
  189. SENDCLIENT(STRING("!e@e NICK :"));
  190. SENDCLIENT(argv[0]);
  191. SENDCLIENT(STRING("\r\n"));
  192. }
  193. free(client_nick.data);
  194. client_nick.data = tmp;
  195. client_nick.len = argv[0].len;
  196. if (client_connected) {
  197. struct user_info *client = get_table_index(user_list, STRING("1HC000001"));
  198. if (client) {
  199. free(client->nick.data);
  200. #pragma GCC diagnostic push
  201. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  202. client->nick.data = name_for_tables; // Will not be used uninitialized, ignore the compiler's complaint here
  203. #pragma GCC diagnostic pop // Compiler sees global variable and assumes it may be changed in one of the functions called between checks
  204. client->nick.len = argv[0].len;
  205. } else {
  206. free(name_for_tables);
  207. WRITES(2, STRING("Client connected but client data missing!\n"));
  208. return 1;
  209. }
  210. SEND(STRING(":1HC000001 NICK "));
  211. SEND(client_nick);
  212. SEND(STRING(" "));
  213. char current_time[22];
  214. snprintf(current_time, 22, "%ld", time(NULL));
  215. SEND(NULSTR(current_time));
  216. SEND(STRING("\n"));
  217. }
  218. return 0;
  219. }
  220. int client_user_handler(uint64_t argc, struct string *argv) {
  221. if (argc < 4)
  222. return 1;
  223. if (client_nick.len == 0)
  224. return 1;
  225. if (add_local_client(STRING("1HC000001"), client_nick, client_hostmask, argv[0], argv[3], time(NULL), 1) != 0)
  226. return 1;
  227. SENDCLIENT(STRING(":"));
  228. SENDCLIENT(server_name);
  229. SENDCLIENT(STRING(" 001 "));
  230. SENDCLIENT(client_nick);
  231. SENDCLIENT(STRING(" :Welcome to the Rexnet IRC Network\r\n:"));
  232. SENDCLIENT(server_name);
  233. SENDCLIENT(STRING(" 002 "));
  234. SENDCLIENT(client_nick);
  235. SENDCLIENT(STRING(" :Your host is "));
  236. SENDCLIENT(server_name);
  237. SENDCLIENT(STRING(", running a totally not sus IRCd\r\n:"));
  238. SENDCLIENT(server_name);
  239. SENDCLIENT(STRING(" 003 "));
  240. SENDCLIENT(client_nick);
  241. SENDCLIENT(STRING(" :This server was created 02:51:36 Apr 03 2023\r\n:"));
  242. SENDCLIENT(server_name);
  243. SENDCLIENT(STRING(" 004 "));
  244. SENDCLIENT(client_nick);
  245. SENDCLIENT(STRING(" "));
  246. SENDCLIENT(server_name);
  247. SENDCLIENT(STRING(" InspIRCd-3 BDGHILNORSTWcdghikorswxz ABCDEFGHIJKLMNOPQRSTXYZabcdefghijklmnopqrstuvwz :BEFHIJLXYZabdefghjkloqvw\r\n:"));
  248. SENDCLIENT(server_name);
  249. SENDCLIENT(STRING(" 005 "));
  250. SENDCLIENT(client_nick);
  251. SENDCLIENT(STRING(" ACCEPT=100 AWAYLEN=200 BOT=B CALLERID=g CASEMAPPING=ascii CHANLIMIT=#:20 CHANMODES=IXZbegw,k,BEFHJLdfjl,ACDGKMNOPQRSTcimnprstuz CHANNELLEN=60 CHANTYPES=# ELIST=CMNTU ESILENCE=CcdiNnPpTtx EXCEPTS=e :are supported by this server\r\n:"));
  252. SENDCLIENT(server_name);
  253. SENDCLIENT(STRING(" 005 "));
  254. SENDCLIENT(client_nick);
  255. SENDCLIENT(STRING(" EXTBAN=,ACNOQRSTUacjmnprswz HOSTLEN=64 INVEX=I KEYLEN=32 KICKLEN=300 LINELEN=512 MAXLIST=I:1000,X:1000,b:1000,e:1000,g:1000,w:1000 MAXTARGETS=20 MODES=20 MONITOR=30 NAMELEN=130 NAMESX NETWORK=LibreIRC :are supported by this server\r\n:"));
  256. SENDCLIENT(server_name);
  257. SENDCLIENT(STRING(" 005 "));
  258. SENDCLIENT(client_nick);
  259. SENDCLIENT(STRING(" NICKLEN=30 OVERRIDE=O PREFIX=(Yqaohv)!~&@%+ REMOVE SAFELIST SECURELIST=60 SILENCE=100 STATUSMSG=!~&@%+ TOPICLEN=330 UHNAMES USERIP USERLEN=10 USERMODES=,,s,BDGHILNORSTWcdghikorwxz :are supported by this server\r\n:"));
  260. SENDCLIENT(server_name);
  261. SENDCLIENT(STRING(" 005 "));
  262. SENDCLIENT(client_nick);
  263. SENDCLIENT(STRING(" WATCH=32 WHOX :are supported by this server\r\n"));
  264. client_connected = 1;
  265. return 0;
  266. }
  267. int client_join_handler(uint64_t argc, struct string *argv) {
  268. if (argc < 1)
  269. return 1;
  270. time_t ctime = time(NULL);
  271. struct string channels = argv[0];
  272. while (1) {
  273. char current_time_nulstr[22];
  274. uint64_t current_time;
  275. if (ctime < 0) {
  276. WRITES(2, STRING("Please check your clock.\n"));
  277. return 1;
  278. }
  279. current_time = (uint64_t)ctime;
  280. uint64_t offset = 0;
  281. while (offset < channels.len && channels.data[offset] != ',')
  282. offset++;
  283. uint64_t oldlen = channels.len;
  284. channels.len = offset;
  285. struct channel_info *channel_info = get_table_index(channel_list, channels);
  286. if (!channel_info) {
  287. channel_info = malloc(sizeof(*channel_info));
  288. if (!channel_info) {
  289. WRITES(2, STRING("OOM! (client_join)\n"));
  290. return 1;
  291. }
  292. *channel_info = (struct channel_info){
  293. .ts = current_time,
  294. .topic = {.data = malloc(0), .len = 0},
  295. .topic_ts = 0,
  296. .modes = {.array = malloc(0), .len = 0},
  297. .user_list = {.array = malloc(0), .len = 0},
  298. .metadata = {.array = malloc(0), .len = 0},
  299. };
  300. set_table_index(&channel_list, channels, channel_info);
  301. }
  302. if (channel_info->ts < current_time)
  303. current_time = channel_info->ts;
  304. snprintf(current_time_nulstr, 22, "%lu", current_time);
  305. SENDCLIENT(STRING(":"));
  306. SENDCLIENT(client_nick);
  307. SENDCLIENT(STRING("!e@e JOIN :"));
  308. SENDCLIENT(channels);
  309. for (uint64_t i = 0; i < channel_info->user_list.len; i++) {
  310. struct string user;
  311. struct user_info *info = channel_info->user_list.array[i].ptr;
  312. if (info)
  313. user = info->nick;
  314. else
  315. user = user_list.array[i].name;
  316. if (i%5 != 0) {
  317. SENDCLIENT(STRING(" "));
  318. SENDCLIENT(user);
  319. } else {
  320. SENDCLIENT(STRING("\r\n:"));
  321. SENDCLIENT(server_name);
  322. SENDCLIENT(STRING(" 353 "));
  323. SENDCLIENT(client_nick);
  324. SENDCLIENT(STRING(" = "));
  325. SENDCLIENT(channels);
  326. SENDCLIENT(STRING(" :"));
  327. SENDCLIENT(user);
  328. }
  329. }
  330. SENDCLIENT(STRING("\r\n:"));
  331. SENDCLIENT(server_name);
  332. SENDCLIENT(STRING(" 366 "));
  333. SENDCLIENT(client_nick);
  334. SENDCLIENT(STRING(" "));
  335. SENDCLIENT(channels);
  336. SENDCLIENT(STRING(" :End of /NAMES list.\r\n"));
  337. SEND(STRING(":1HC FJOIN "));
  338. SEND(channels);
  339. SEND(STRING(" "));
  340. SEND(NULSTR(current_time_nulstr));
  341. SEND(STRING(" + :,1HC000001\n"));
  342. set_table_index(&(channel_info->user_list), STRING("1HC000001"), get_table_index(user_list, STRING("1HC000001"))); // TODO: Actually add local users to user_list
  343. channels.len = oldlen;
  344. if (channels.len <= offset+1)
  345. break;
  346. channels.data += offset + 1;
  347. channels.len -= offset + 1;
  348. }
  349. return 0;
  350. }
  351. int client_privmsg_handler(uint64_t argc, struct string *argv) {
  352. if (argc < 2)
  353. return 1;
  354. SEND(STRING(":1HC000001 PRIVMSG "));
  355. SEND(argv[0]);
  356. SEND(STRING(" :"));
  357. SEND(argv[1]);
  358. SEND(STRING("\n"));
  359. uint64_t offset;
  360. if (argv[0].data[0] == '#') {
  361. if (argv[1].len < command_prefix.len || memcmp(argv[1].data, command_prefix.data, command_prefix.len) != 0)
  362. return 0;
  363. offset = command_prefix.len;
  364. } else {
  365. offset = 0;
  366. }
  367. if (offset >= argv[1].len || argv[1].data[offset] == ' ')
  368. return 0;
  369. uint64_t command_argc = 0;
  370. uint64_t old_offset = offset;
  371. while (offset < argv[1].len) {
  372. while (offset < argv[1].len && argv[1].data[offset] != ' ')
  373. offset++;
  374. command_argc++;
  375. while (offset < argv[1].len && argv[1].data[offset] == ' ')
  376. offset++;
  377. }
  378. offset = old_offset;
  379. struct string command_argv[command_argc]; // argv[0] in this case is the command itself, unlike network command handlers... might change one of these two later to match
  380. uint64_t i = 0;
  381. while (offset < argv[1].len) {
  382. command_argv[i].data = argv[1].data+offset;
  383. uint64_t start = offset;
  384. while (offset < argv[1].len && argv[1].data[offset] != ' ')
  385. offset++;
  386. command_argv[i].len = offset - start;
  387. while (offset < argv[1].len && argv[1].data[offset] == ' ')
  388. offset++;
  389. i++;
  390. }
  391. argv[1].data += old_offset;
  392. argv[1].len -= old_offset;
  393. struct command_def *cmd = get_table_index(user_commands, command_argv[0]);
  394. if (cmd) {
  395. struct string message[] = {
  396. STRING("Local user "),
  397. client_nick,
  398. STRING(" executes `"),
  399. argv[1],
  400. STRING("'"),
  401. };
  402. privmsg(STRING("1HC000000"), log_channel, sizeof(message)/sizeof(*message), message);
  403. return cmd->func(STRING("1HC000001"), argv[1], argv[0], command_argc, command_argv, 1);
  404. } else {
  405. if (argv[0].data[0] == '#') {
  406. SEND(STRING(":1HC000000 NOTICE "));
  407. SEND(argv[0]);
  408. SEND(STRING(" :Unknown command: "));
  409. SEND(command_prefix);
  410. SEND(command_argv[0]);
  411. SEND(STRING("\n"));
  412. }
  413. return 0;
  414. }
  415. return 0;
  416. }
  417. int client_raw_handler(uint64_t argc, struct string *argv) {
  418. if (argc < 1)
  419. return 1;
  420. SEND(argv[0]);
  421. SEND(STRING("\n"));
  422. return 0;
  423. }
  424. int client_ping_handler(uint64_t argc, struct string *argv) {
  425. if (argc < 1)
  426. return 1;
  427. SENDCLIENT(STRING(":"));
  428. SENDCLIENT(server_name);
  429. SENDCLIENT(STRING(" PONG :"));
  430. SENDCLIENT(argv[0]);
  431. SENDCLIENT(STRING("\r\n"));
  432. return 0;
  433. }
  434. int client_mode_handler(uint64_t argc, struct string *argv) {
  435. if (argc < 2)
  436. return 0; // Mode querying not supported yet
  437. SEND(STRING(":1HC000001 MODE "));
  438. for (uint64_t i = 0; i < argc - 1; i++) {
  439. SEND(argv[i]);
  440. SEND(STRING(" "));
  441. }
  442. SEND(STRING(":"));
  443. SEND(argv[argc - 1]);
  444. SEND(STRING("\n"));
  445. return 0;
  446. }
  447. int client_fd = -1;
  448. int client_listen_fd;
  449. int initclientnetwork(void) {
  450. client_network_commands.array = malloc(0);
  451. set_table_index(&client_network_commands, STRING("NICK"), &client_nick_handler);
  452. set_table_index(&client_network_commands, STRING("USER"), &client_user_handler);
  453. set_table_index(&client_network_commands, STRING("JOIN"), &client_join_handler);
  454. set_table_index(&client_network_commands, STRING("PRIVMSG"), &client_privmsg_handler);
  455. set_table_index(&client_network_commands, STRING("RAW"), &client_raw_handler);
  456. set_table_index(&client_network_commands, STRING("PING"), &client_ping_handler);
  457. set_table_index(&client_network_commands, STRING("MODE"), &client_mode_handler);
  458. client_nick.data = malloc(0);
  459. client_listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  460. if (client_listen_fd < 0)
  461. return 1;
  462. int one = 1;
  463. setsockopt(client_listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
  464. struct sockaddr_in localhost = {
  465. .sin_family = AF_INET,
  466. .sin_port = htons(6667),
  467. };
  468. inet_pton(AF_INET, "127.0.0.1", &localhost.sin_addr); // this is indeed localhost for mine, and I have no intent to change this
  469. bind(client_listen_fd, (struct sockaddr*)&localhost, sizeof(localhost));
  470. listen(client_listen_fd, 1);
  471. return 0;
  472. }
  473. #if LOGALL
  474. ssize_t SENDCLIENT(struct string msg) {
  475. if (msg.len == 0 || client_fd == -1)
  476. return 0;
  477. static char printprefix = 1;
  478. if (printprefix) {
  479. #if COLORIZE
  480. WRITES(1, STRING("\x1b[31m[Us->Client] \x1b[32m"));
  481. #else
  482. WRITES(1, STRING("[Us->Client] "));
  483. #endif
  484. printprefix = 0;
  485. }
  486. WRITES(1, msg);
  487. if (msg.data[msg.len - 1] == '\n') {
  488. printprefix = 1;
  489. #if COLORIZE
  490. WRITES(1, STRING("\x1b[0m\n"));
  491. #else
  492. WRITES(1, STRING("\n"));
  493. #endif
  494. }
  495. return WRITES(client_fd, msg);
  496. }
  497. #endif