IRC bouncer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bounce.h 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* Copyright (C) 2019 C. McEnroe <june@causal.agency>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. */
  16. #include <stdbool.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <time.h>
  21. #include <tls.h>
  22. #include "compat.h"
  23. #ifndef CERTBOT_PATH
  24. #define CERTBOT_PATH "/usr/local/etc/letsencrypt"
  25. #endif
  26. #define SOURCE_URL "https://code.causal.agency/june/pounce"
  27. #define ORIGIN "irc.invalid"
  28. #define BIT(x) x##Bit, x = 1 << x##Bit, x##Bit_ = x##Bit
  29. #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
  30. typedef unsigned char byte;
  31. enum { ParamCap = 15 };
  32. struct Message {
  33. char *origin;
  34. char *cmd;
  35. char *params[ParamCap];
  36. };
  37. static inline struct Message parse(char *line) {
  38. struct Message msg = {0};
  39. if (line[0] == ':') msg.origin = 1 + strsep(&line, " ");
  40. msg.cmd = strsep(&line, " ");
  41. for (size_t i = 0; line && i < ParamCap; ++i) {
  42. if (line[0] == ':') {
  43. msg.params[i] = &line[1];
  44. break;
  45. }
  46. msg.params[i] = strsep(&line, " ");
  47. }
  48. return msg;
  49. }
  50. #define ENUM_CAP \
  51. X("account-notify", CapAccountNotify) \
  52. X("away-notify", CapAwayNotify) \
  53. X("chghost", CapChghost) \
  54. X("extended-join", CapExtendedJoin) \
  55. X("invite-notify", CapInviteNotify) \
  56. X("sasl", CapSASL) \
  57. X("server-time", CapServerTime) \
  58. X("userhost-in-names", CapUserhostInNames) \
  59. X("", CapUnsupported)
  60. enum Cap {
  61. #define X(name, id) BIT(id),
  62. ENUM_CAP
  63. #undef X
  64. };
  65. static const char *CapNames[] = {
  66. #define X(name, id) [id##Bit] = name,
  67. ENUM_CAP
  68. #undef X
  69. };
  70. static inline enum Cap capParse(const char *list) {
  71. enum Cap caps = 0;
  72. while (*list) {
  73. enum Cap cap = CapUnsupported;
  74. size_t len = strcspn(list, " ");
  75. for (size_t i = 0; i < ARRAY_LEN(CapNames); ++i) {
  76. if (len != strlen(CapNames[i])) continue;
  77. if (strncmp(list, CapNames[i], len)) continue;
  78. cap = 1 << i;
  79. break;
  80. }
  81. caps |= cap;
  82. list += len;
  83. if (*list) list++;
  84. }
  85. return caps;
  86. }
  87. static inline const char *capList(enum Cap caps) {
  88. static char buf[1024];
  89. buf[0] = '\0';
  90. for (size_t i = 0; i < ARRAY_LEN(CapNames); ++i) {
  91. if (caps & (1 << i)) {
  92. if (buf[0]) strlcat(buf, " ", sizeof(buf));
  93. strlcat(buf, CapNames[i], sizeof(buf));
  94. }
  95. }
  96. return buf;
  97. }
  98. bool verbose;
  99. void ringAlloc(size_t len);
  100. void ringProduce(const char *line);
  101. size_t ringConsumer(const char *name);
  102. size_t ringDiff(size_t consumer);
  103. const char *ringPeek(time_t *time, size_t consumer);
  104. const char *ringConsume(time_t *time, size_t consumer);
  105. void ringInfo(void);
  106. int ringSave(FILE *file);
  107. void ringLoad(FILE *file);
  108. void localConfig(FILE *cert, FILE *priv);
  109. size_t localBind(int fds[], size_t cap, const char *host, const char *port);
  110. size_t localUnix(int fds[], size_t cap, const char *path);
  111. struct tls *localAccept(int *fd, int bind);
  112. void serverConfig(bool insecure, const char *cert, const char *priv);
  113. int serverConnect(const char *host, const char *port);
  114. void serverRecv(void);
  115. void serverSend(const char *ptr, size_t len);
  116. void serverFormat(const char *format, ...)
  117. __attribute__((format(printf, 1, 2)));
  118. char *clientPass;
  119. char *clientAway;
  120. struct Client *clientAlloc(struct tls *tls);
  121. void clientFree(struct Client *client);
  122. bool clientError(const struct Client *client);
  123. void clientRecv(struct Client *client);
  124. void clientSend(struct Client *client, const char *ptr, size_t len);
  125. void clientFormat(struct Client *client, const char *format, ...)
  126. __attribute__((format(printf, 2, 3)));
  127. size_t clientDiff(const struct Client *client);
  128. void clientConsume(struct Client *client);
  129. bool stateJoinNames;
  130. enum Cap stateCaps;
  131. void stateLogin(
  132. const char *pass, bool sasl, const char *plain,
  133. const char *nick, const char *user, const char *real
  134. );
  135. bool stateReady(void);
  136. void stateParse(char *line);
  137. void stateSync(struct Client *client);
  138. const char *stateNick(void);
  139. const char *stateEcho(void);
  140. struct option;
  141. int getopt_config(
  142. int argc, char *const *argv,
  143. const char *optstring, const struct option *longopts, int *longindex
  144. );
  145. static const char Base64[64] = {
  146. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  147. };
  148. #define BASE64_SIZE(len) (1 + ((len) + 2) / 3 * 4)
  149. static inline void base64(char *dst, const byte *src, size_t len) {
  150. size_t i = 0;
  151. while (len > 2) {
  152. dst[i++] = Base64[0x3F & (src[0] >> 2)];
  153. dst[i++] = Base64[0x3F & (src[0] << 4 | src[1] >> 4)];
  154. dst[i++] = Base64[0x3F & (src[1] << 2 | src[2] >> 6)];
  155. dst[i++] = Base64[0x3F & src[2]];
  156. src += 3;
  157. len -= 3;
  158. }
  159. if (len) {
  160. dst[i++] = Base64[0x3F & (src[0] >> 2)];
  161. if (len > 1) {
  162. dst[i++] = Base64[0x3F & (src[0] << 4 | src[1] >> 4)];
  163. dst[i++] = Base64[0x3F & (src[1] << 2)];
  164. } else {
  165. dst[i++] = Base64[0x3F & (src[0] << 4)];
  166. dst[i++] = '=';
  167. }
  168. dst[i++] = '=';
  169. }
  170. dst[i] = '\0';
  171. }