📄 si.c
字号:
/* * purple - Jabber Protocol Plugin * * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include "blist.h"#include "internal.h"#include "cipher.h"#include "debug.h"#include "ft.h"#include "request.h"#include "network.h"#include "notify.h"#include "buddy.h"#include "disco.h"#include "jabber.h"#include "iq.h"#include "si.h"#include "si.h"struct bytestreams_streamhost { char *jid; char *host; int port;};typedef struct _JabberSIXfer { JabberStream *js; PurpleProxyConnectData *connect_data; PurpleNetworkListenData *listen_data; gboolean accepted; char *stream_id; char *iq_id; enum { STREAM_METHOD_UNKNOWN = 0, STREAM_METHOD_BYTESTREAMS = 2 << 1, STREAM_METHOD_IBB = 2 << 2, STREAM_METHOD_UNSUPPORTED = 2 << 31 } stream_method; GList *streamhosts; PurpleProxyInfo *gpi; char *rxqueue; size_t rxlen; gsize rxmaxlen;} JabberSIXfer;static PurpleXfer*jabber_si_xfer_find(JabberStream *js, const char *sid, const char *from){ GList *xfers; if(!sid || !from) return NULL; for(xfers = js->file_transfers; xfers; xfers = xfers->next) { PurpleXfer *xfer = xfers->data; JabberSIXfer *jsx = xfer->data; if(jsx->stream_id && xfer->who && !strcmp(jsx->stream_id, sid) && !strcmp(xfer->who, from)) return xfer; } return NULL;}static void jabber_si_bytestreams_attempt_connect(PurpleXfer *xfer);static voidjabber_si_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message){ PurpleXfer *xfer = data; JabberSIXfer *jsx = xfer->data; JabberIq *iq; xmlnode *query, *su; struct bytestreams_streamhost *streamhost = jsx->streamhosts->data; purple_proxy_info_destroy(jsx->gpi); jsx->connect_data = NULL; if(source < 0) { purple_debug_warning("jabber", "si connection failed, jid was %s, host was %s, error was %s\n", streamhost->jid, streamhost->host, error_message); jsx->streamhosts = g_list_remove(jsx->streamhosts, streamhost); g_free(streamhost->jid); g_free(streamhost->host); g_free(streamhost); jabber_si_bytestreams_attempt_connect(xfer); return; } iq = jabber_iq_new_query(jsx->js, JABBER_IQ_RESULT, "http://jabber.org/protocol/bytestreams"); xmlnode_set_attrib(iq->node, "to", xfer->who); jabber_iq_set_id(iq, jsx->iq_id); query = xmlnode_get_child(iq->node, "query"); su = xmlnode_new_child(query, "streamhost-used"); xmlnode_set_attrib(su, "jid", streamhost->jid); jabber_iq_send(iq); purple_xfer_start(xfer, source, NULL, -1);}static void jabber_si_bytestreams_attempt_connect(PurpleXfer *xfer){ JabberSIXfer *jsx = xfer->data; struct bytestreams_streamhost *streamhost; char *dstaddr, *p; int i; unsigned char hashval[20]; JabberID *dstjid; if(!jsx->streamhosts) { JabberIq *iq = jabber_iq_new(jsx->js, JABBER_IQ_ERROR); xmlnode *error, *inf; if(jsx->iq_id) jabber_iq_set_id(iq, jsx->iq_id); xmlnode_set_attrib(iq->node, "to", xfer->who); error = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error, "code", "404"); xmlnode_set_attrib(error, "type", "cancel"); inf = xmlnode_new_child(error, "item-not-found"); xmlnode_set_namespace(inf, "urn:ietf:params:xml:ns:xmpp-stanzas"); jabber_iq_send(iq); purple_xfer_cancel_local(xfer); return; } streamhost = jsx->streamhosts->data; dstjid = jabber_id_new(xfer->who); if(dstjid != NULL) { jsx->gpi = purple_proxy_info_new(); purple_proxy_info_set_type(jsx->gpi, PURPLE_PROXY_SOCKS5); purple_proxy_info_set_host(jsx->gpi, streamhost->host); purple_proxy_info_set_port(jsx->gpi, streamhost->port); dstaddr = g_strdup_printf("%s%s@%s/%s%s@%s/%s", jsx->stream_id, dstjid->node, dstjid->domain, dstjid->resource, jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource); purple_cipher_digest_region("sha1", (guchar *)dstaddr, strlen(dstaddr), sizeof(hashval), hashval, NULL); g_free(dstaddr); dstaddr = g_malloc(41); p = dstaddr; for(i=0; i<20; i++, p+=2) snprintf(p, 3, "%02x", hashval[i]); jsx->connect_data = purple_proxy_connect_socks5(NULL, jsx->gpi, dstaddr, 0, jabber_si_bytestreams_connect_cb, xfer); g_free(dstaddr); jabber_id_free(dstjid); } if (jsx->connect_data == NULL) { jsx->streamhosts = g_list_remove(jsx->streamhosts, streamhost); g_free(streamhost->jid); g_free(streamhost->host); g_free(streamhost); jabber_si_bytestreams_attempt_connect(xfer); }}void jabber_bytestreams_parse(JabberStream *js, xmlnode *packet){ PurpleXfer *xfer; JabberSIXfer *jsx; xmlnode *query, *streamhost; const char *sid, *from, *type; if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "set")) return; if(!(from = xmlnode_get_attrib(packet, "from"))) return; if(!(query = xmlnode_get_child(packet, "query"))) return; if(!(sid = xmlnode_get_attrib(query, "sid"))) return; if(!(xfer = jabber_si_xfer_find(js, sid, from))) return; jsx = xfer->data; if(!jsx->accepted) return; if(jsx->iq_id) g_free(jsx->iq_id); jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id")); for(streamhost = xmlnode_get_child(query, "streamhost"); streamhost; streamhost = xmlnode_get_next_twin(streamhost)) { const char *jid, *host, *port; int portnum; if((jid = xmlnode_get_attrib(streamhost, "jid")) && (host = xmlnode_get_attrib(streamhost, "host")) && (port = xmlnode_get_attrib(streamhost, "port")) && (portnum = atoi(port))) { struct bytestreams_streamhost *sh = g_new0(struct bytestreams_streamhost, 1); sh->jid = g_strdup(jid); sh->host = g_strdup(host); sh->port = portnum; jsx->streamhosts = g_list_append(jsx->streamhosts, sh); } } jabber_si_bytestreams_attempt_connect(xfer);}static voidjabber_si_xfer_bytestreams_send_read_again_resp_cb(gpointer data, gint source, PurpleInputCondition cond){ PurpleXfer *xfer = data; JabberSIXfer *jsx = xfer->data; int len; len = write(source, jsx->rxqueue + jsx->rxlen, jsx->rxmaxlen - jsx->rxlen); if (len < 0 && errno == EAGAIN) return; else if (len < 0) { purple_input_remove(xfer->watcher); xfer->watcher = 0; g_free(jsx->rxqueue); jsx->rxqueue = NULL; close(source); purple_xfer_cancel_remote(xfer); return; } jsx->rxlen += len; if (jsx->rxlen < jsx->rxmaxlen) return; purple_input_remove(xfer->watcher); xfer->watcher = 0; g_free(jsx->rxqueue); jsx->rxqueue = NULL; purple_xfer_start(xfer, source, NULL, -1);}static voidjabber_si_xfer_bytestreams_send_read_again_cb(gpointer data, gint source, PurpleInputCondition cond){ PurpleXfer *xfer = data; JabberSIXfer *jsx = xfer->data; int i; char buffer[256]; int len; char *dstaddr, *p; unsigned char hashval[20]; const char *host; purple_debug_info("jabber", "in jabber_si_xfer_bytestreams_send_read_again_cb\n"); if(jsx->rxlen < 5) { purple_debug_info("jabber", "reading the first 5 bytes\n"); len = read(source, buffer, 5 - jsx->rxlen); if(len < 0 && errno == EAGAIN) return; else if(len <= 0) { purple_input_remove(xfer->watcher); xfer->watcher = 0; close(source); purple_xfer_cancel_remote(xfer); return; } jsx->rxqueue = g_realloc(jsx->rxqueue, len + jsx->rxlen); memcpy(jsx->rxqueue + jsx->rxlen, buffer, len); jsx->rxlen += len; return; } else if(jsx->rxqueue[0] != 0x05 || jsx->rxqueue[1] != 0x01 || jsx->rxqueue[3] != 0x03) { purple_debug_info("jabber", "invalid socks5 stuff\n"); purple_input_remove(xfer->watcher); xfer->watcher = 0; close(source); purple_xfer_cancel_remote(xfer); return; } else if(jsx->rxlen - 5 < jsx->rxqueue[4] + 2) { purple_debug_info("jabber", "reading umpteen more bytes\n"); len = read(source, buffer, jsx->rxqueue[4] + 5 + 2 - jsx->rxlen); if(len < 0 && errno == EAGAIN) return; else if(len <= 0) { purple_input_remove(xfer->watcher); xfer->watcher = 0; close(source); purple_xfer_cancel_remote(xfer); return; } jsx->rxqueue = g_realloc(jsx->rxqueue, len + jsx->rxlen); memcpy(jsx->rxqueue + jsx->rxlen, buffer, len); jsx->rxlen += len; } if(jsx->rxlen - 5 < jsx->rxqueue[4] + 2) return; purple_input_remove(xfer->watcher); xfer->watcher = 0; dstaddr = g_strdup_printf("%s%s@%s/%s%s", jsx->stream_id, jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource, xfer->who); purple_cipher_digest_region("sha1", (guchar *)dstaddr, strlen(dstaddr), sizeof(hashval), hashval, NULL); g_free(dstaddr); dstaddr = g_malloc(41); p = dstaddr; for(i=0; i<20; i++, p+=2) snprintf(p, 3, "%02x", hashval[i]); if(jsx->rxqueue[4] != 40 || strncmp(dstaddr, jsx->rxqueue+5, 40) || jsx->rxqueue[45] != 0x00 || jsx->rxqueue[46] != 0x00) { purple_debug_error("jabber", "someone connected with the wrong info!\n"); close(source); purple_xfer_cancel_remote(xfer); return; } g_free(jsx->rxqueue); host = purple_network_get_my_ip(jsx->js->fd); jsx->rxmaxlen = 5 + strlen(host) + 2; jsx->rxqueue = g_malloc(jsx->rxmaxlen); jsx->rxlen = 0; jsx->rxqueue[0] = 0x05; jsx->rxqueue[1] = 0x00; jsx->rxqueue[2] = 0x00; jsx->rxqueue[3] = 0x03; jsx->rxqueue[4] = strlen(host); memcpy(jsx->rxqueue + 5, host, strlen(host)); jsx->rxqueue[5+strlen(host)] = 0x00; jsx->rxqueue[6+strlen(host)] = 0x00; xfer->watcher = purple_input_add(source, PURPLE_INPUT_WRITE, jabber_si_xfer_bytestreams_send_read_again_resp_cb, xfer); jabber_si_xfer_bytestreams_send_read_again_resp_cb(xfer, source, PURPLE_INPUT_WRITE);}static voidjabber_si_xfer_bytestreams_send_read_response_cb(gpointer data, gint source, PurpleInputCondition cond){ PurpleXfer *xfer = data; JabberSIXfer *jsx = xfer->data; int len; len = write(source, jsx->rxqueue + jsx->rxlen, jsx->rxmaxlen - jsx->rxlen); if (len < 0 && errno == EAGAIN) return; else if (len < 0) { purple_input_remove(xfer->watcher); xfer->watcher = 0; g_free(jsx->rxqueue); jsx->rxqueue = NULL; close(source); purple_xfer_cancel_remote(xfer); return; } jsx->rxlen += len; if (jsx->rxlen < jsx->rxmaxlen) return; purple_input_remove(xfer->watcher); xfer->watcher = 0; if (jsx->rxqueue[1] == 0x00) { xfer->watcher = purple_input_add(source, PURPLE_INPUT_READ, jabber_si_xfer_bytestreams_send_read_again_cb, xfer); g_free(jsx->rxqueue); jsx->rxqueue = NULL; } else { close(source); purple_xfer_cancel_remote(xfer); }}static voidjabber_si_xfer_bytestreams_send_read_cb(gpointer data, gint source, PurpleInputCondition cond){ PurpleXfer *xfer = data; JabberSIXfer *jsx = xfer->data; int i; int len; char buffer[256]; purple_debug_info("jabber", "in jabber_si_xfer_bytestreams_send_read_cb\n"); xfer->fd = source; if(jsx->rxlen < 2) { purple_debug_info("jabber", "reading those first two bytes\n"); len = read(source, buffer, 2 - jsx->rxlen); if(len < 0 && errno == EAGAIN) return; else if(len <= 0) { purple_input_remove(xfer->watcher); xfer->watcher = 0; close(source); purple_xfer_cancel_remote(xfer); return; } jsx->rxqueue = g_realloc(jsx->rxqueue, len + jsx->rxlen); memcpy(jsx->rxqueue + jsx->rxlen, buffer, len); jsx->rxlen += len; return; } else if(jsx->rxlen - 2 < jsx->rxqueue[1]) { purple_debug_info("jabber", "reading the next umpteen bytes\n"); len = read(source, buffer, jsx->rxqueue[1] + 2 - jsx->rxlen); if(len < 0 && errno == EAGAIN) return; else if(len <= 0) { purple_input_remove(xfer->watcher); xfer->watcher = 0; close(source); purple_xfer_cancel_remote(xfer); return; } jsx->rxqueue = g_realloc(jsx->rxqueue, len + jsx->rxlen); memcpy(jsx->rxqueue + jsx->rxlen, buffer, len); jsx->rxlen += len; } if(jsx->rxlen -2 < jsx->rxqueue[1]) return; purple_input_remove(xfer->watcher); xfer->watcher = 0; purple_debug_info("jabber", "checking to make sure we're socks FIVE\n"); if(jsx->rxqueue[0] != 0x05) { close(source); purple_xfer_cancel_remote(xfer); return; } purple_debug_info("jabber", "going to test %hhu different methods\n", jsx->rxqueue[1]); for(i=0; i<jsx->rxqueue[1]; i++) { purple_debug_info("jabber", "testing %hhu\n", jsx->rxqueue[i+2]); if(jsx->rxqueue[i+2] == 0x00) { g_free(jsx->rxqueue); jsx->rxlen = 0; jsx->rxmaxlen = 2; jsx->rxqueue = g_malloc(jsx->rxmaxlen); jsx->rxqueue[0] = 0x05; jsx->rxqueue[1] = 0x00; xfer->watcher = purple_input_add(source, PURPLE_INPUT_WRITE, jabber_si_xfer_bytestreams_send_read_response_cb, xfer); jabber_si_xfer_bytestreams_send_read_response_cb(xfer, source, PURPLE_INPUT_WRITE); jsx->rxqueue = NULL; jsx->rxlen = 0; return; } } g_free(jsx->rxqueue); jsx->rxlen = 0; jsx->rxmaxlen = 2; jsx->rxqueue = g_malloc(jsx->rxmaxlen); jsx->rxqueue[0] = 0x05; jsx->rxqueue[1] = 0xFF; xfer->watcher = purple_input_add(source, PURPLE_INPUT_WRITE, jabber_si_xfer_bytestreams_send_read_response_cb, xfer); jabber_si_xfer_bytestreams_send_read_response_cb(xfer, source, PURPLE_INPUT_WRITE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -