#include "barev_ft.h" #include "barev_sha1.h" #include #include #include #include #include #include #include #include #include static int has_ns(const char *xml, const char *ns) { char a[256], b[256]; if (!xml || !ns) return 0; (void)snprintf(a, sizeof(a), "xmlns=\"%s\"", ns); (void)snprintf(b, sizeof(b), "xmlns='%s'", ns); return (strstr(xml, a) != 0 || strstr(xml, b) != 0) ? 1 : 0; } int barev_ft_extract_attr(const char *xml, const char *attr, char *out, unsigned long out_n) { char p1[128], p2[128]; const char *p, *q; unsigned long n; if (!xml || !attr || !out || out_n == 0) return 0; out[0] = '\0'; snprintf(p1, sizeof(p1), "%s=\"", attr); snprintf(p2, sizeof(p2), "%s='", attr); p = strstr(xml, p1); if (!p) p = strstr(xml, p2); if (!p) return 0; p += (p[strlen(attr) + 1] == '"') ? strlen(p1) : strlen(p2); q = p; while (*q && *q != '"' && *q != '\'') q++; n = (unsigned long)(q - p); if (n + 1 > out_n) return 0; memcpy(out, p, (size_t)n); out[n] = '\0'; return 1; } static int rd_exact(int fd, unsigned char *buf, int n) { int got = 0, r; while (got < n) { r = (int)read(fd, buf + got, (size_t)(n - got)); if (r <= 0) return 0; got += r; } return 1; } static int wr_exact(int fd, const unsigned char *buf, int n) { int done = 0, w; while (done < n) { w = (int)write(fd, buf + done, (size_t)(n - done)); if (w <= 0) return 0; done += w; } return 1; } int barev_ft_socks5_server_handshake(int sockfd) { unsigned char b[512]; int nmethods; if (!rd_exact(sockfd, b, 2)) return 0; if (b[0] != 5) return 0; nmethods = b[1]; if (nmethods > 0) { if (nmethods > 255) return 0; if (!rd_exact(sockfd, b, nmethods)) return 0; } b[0] = 5; b[1] = 0; if (!wr_exact(sockfd, b, 2)) return 0; /* Tolerant: just consume some request bytes, as Pascal does. */ nmethods = (int)read(sockfd, b, sizeof(b)); if (nmethods <= 0) return 0; b[0] = 5; b[1] = 0; b[2] = 0; b[3] = 3; b[4] = 20; memset(b + 5, 0, 20); b[25] = 0; b[26] = 0; if (!wr_exact(sockfd, b, 27)) return 0; return 1; } int barev_ft_socks5_client_handshake(int sockfd, const char *dstaddr40) { unsigned char b[512]; int i, r; unsigned char l; if (!dstaddr40) return 0; b[0] = 5; b[1] = 1; b[2] = 0; if (!wr_exact(sockfd, b, 3)) return 0; if (!rd_exact(sockfd, b, 2)) return 0; if (b[0] != 5 || b[1] != 0) return 0; b[0] = 5; b[1] = 1; b[2] = 0; b[3] = 3; l = 40; b[4] = l; for (i = 0; i < 40; ++i) b[5 + i] = (unsigned char)dstaddr40[i]; b[45] = 0; b[46] = 0; if (!wr_exact(sockfd, b, 47)) return 0; if (!rd_exact(sockfd, b, 5)) return 0; if (b[0] != 5 || b[1] != 0) return 0; if (b[3] == 1) r = 4 + 2; else if (b[3] == 3) r = b[4] + 2; else if (b[3] == 4) r = 16 + 2; else return 0; if (r > 0) { if (r > (int)sizeof(b)) return 0; if (!rd_exact(sockfd, b, r)) return 0; } return 1; } int barev_ft_build_si_offer(const char *from_jid, const char *to_jid, const char *id, const char *sid, const char *file_name, long file_size, char *out, unsigned long out_n) { int w; if (!from_jid || !to_jid || !id || !sid || !file_name || !out || out_n == 0) return 0; w = snprintf(out, (size_t)out_n, "" "" "" "" "" "" "" "" "" "" "" "", id, from_jid, to_jid, sid, file_name, file_size); return (w > 0 && (unsigned long)w < out_n) ? 1 : 0; } int barev_ft_build_si_accept(const char *from_jid, const char *to_jid, const char *id, char *out, unsigned long out_n) { int w; if (!from_jid || !to_jid || !id || !out || out_n == 0) return 0; w = snprintf(out, (size_t)out_n, "" "" "" "" "" "http://jabber.org/protocol/bytestreams" "" "" "" "" "", id, from_jid, to_jid); return (w > 0 && (unsigned long)w < out_n) ? 1 : 0; } int barev_ft_build_si_reject(const char *from_jid, const char *to_jid, const char *id, const char *code, char *out, unsigned long out_n) { int w; if (!from_jid || !to_jid || !id || !out || out_n == 0) return 0; if (!code || !code[0]) code = "403"; w = snprintf(out, (size_t)out_n, "" "" "", id, from_jid, to_jid, code); return (w > 0 && (unsigned long)w < out_n) ? 1 : 0; } int barev_ft_build_bytestreams_query(const char *from_jid, const char *to_jid, const char *id, const char *sid, const char *host, unsigned short port, char *out, unsigned long out_n) { int w; if (!from_jid || !to_jid || !id || !sid || !host || !out || out_n == 0) return 0; w = snprintf(out, (size_t)out_n, "" "" "" "" "", id, from_jid, to_jid, sid, from_jid, host, (unsigned)port); return (w > 0 && (unsigned long)w < out_n) ? 1 : 0; } int barev_ft_build_bytestreams_used(const char *from_jid, const char *to_jid, const char *id, const char *sid, const char *host_jid, char *out, unsigned long out_n) { int w; if (!from_jid || !to_jid || !id || !sid || !host_jid || !out || out_n == 0) return 0; w = snprintf(out, (size_t)out_n, "" "" "" "" "", id, from_jid, to_jid, sid, host_jid); return (w > 0 && (unsigned long)w < out_n) ? 1 : 0; } int barev_ft_is_si_offer(const char *xml) { if (!xml) return 0; if (strstr(xml, " sizeof(tmp)) return 0; memcpy(tmp, sid, n1); memcpy(tmp + n1, initiator_jid, n2); memcpy(tmp + n1 + n2, target_jid, n3); tmp[n1 + n2 + n3] = '\0'; barev_sha1_hex((const unsigned char *)tmp, n1 + n2 + n3, out40); return 1; } int barev_ft_recv_file_blocking(int sockfd, const char *save_path, long expected_size, long *bytes_done) { int fd; unsigned char buf[8192]; ssize_t r; long done = 0; if (!save_path || expected_size < 0) return 0; fd = open(save_path, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (fd < 0) return 0; while (done < expected_size) { r = read(sockfd, buf, sizeof(buf)); if (r <= 0) break; if (write(fd, buf, (size_t)r) != r) { close(fd); return 0; } done += (long)r; } close(fd); if (bytes_done) *bytes_done = done; return done >= expected_size ? 1 : 0; } int barev_ft_listen_range(unsigned short min_port, unsigned short max_port, unsigned short *bound_port) { int s, on; struct sockaddr_in6 sa; unsigned short p; s = socket(AF_INET6, SOCK_STREAM, 0); if (s < 0) return -1; on = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; sa.sin6_addr = in6addr_any; for (p = min_port; p <= max_port; ++p) { sa.sin6_port = htons(p); if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == 0) { if (listen(s, 1) == 0) { if (bound_port) *bound_port = p; return s; } } } close(s); return -1; } int barev_ft_send_file_blocking(int sockfd, const char *path, long *bytes_done) { int fd; unsigned char buf[8192]; ssize_t r, w; long done = 0; if (!path) return 0; fd = open(path, O_RDONLY); if (fd < 0) return 0; for (;;) { r = read(fd, buf, sizeof(buf)); if (r < 0) { close(fd); return 0; } if (r == 0) break; w = write(sockfd, buf, (size_t)r); if (w != r) { close(fd); return 0; } done += (long)w; } close(fd); if (bytes_done) *bytes_done = done; return 1; }