jingle-s5b/socks5.c
changeset 159 1df5f5e3f1e7
parent 158 a068e5714120
child 161 fa1d993d05b6
equal deleted inserted replaced
158:a068e5714120 159:1df5f5e3f1e7
    98 };
    98 };
    99 
    99 
   100 typedef struct {
   100 typedef struct {
   101   GInetAddress *address;
   101   GInetAddress *address;
   102   guint32       priority;
   102   guint32       priority;
   103 } LocalCandidate;
   103 } LocalIP;
   104 
   104 
   105 /**
   105 /**
   106  * @brief Linked list of candidates to send on session-initiate
   106  * @brief Linked list of candidates to send on session-initiate
   107  */
   107  */
   108 static GSList *local_candidates = NULL;
   108 static GSList *local_ips = NULL;
   109 
   109 
   110 
   110 
   111 static gint index_in_array(const gchar *str, const gchar **array)
   111 static gint index_in_array(const gchar *str, const gchar **array)
   112 {
   112 {
   113   gint i;
   113   gint i;
   136  * @return a list of S5BCandidate
   136  * @return a list of S5BCandidate
   137  */
   137  */
   138 static GSList *parse_candidates(LmMessageNode *node)
   138 static GSList *parse_candidates(LmMessageNode *node)
   139 {
   139 {
   140   LmMessageNode *node2;
   140   LmMessageNode *node2;
   141   GSList *list;
   141   GSList *list = NULL;
   142 
   142 
   143   for (node2 = node->children; node2; node2 = node2->next) {
   143   for (node2 = node->children; node2; node2 = node2->next) {
   144     if (g_strcmp0(node->name, "candidate"))
   144     if (g_strcmp0(node->name, "candidate"))
   145         continue;
   145         continue;
   146     const gchar *portstr, *prioritystr, *typestr;
   146     const gchar *portstr, *prioritystr, *typestr;
   169   }
   169   }
   170   list = g_slist_sort(list, prioritycmp);
   170   list = g_slist_sort(list, prioritycmp);
   171   return list;
   171   return list;
   172 }
   172 }
   173 
   173 
   174 static gconstpointer newfrommessage(JingleContent *cn, GError **err)
   174 static GSList *get_our_candidates(guint16 port)
   175 {
   175 {
   176   JingleS5B *js5b;
   176   GSList *our_candidates = NULL, *entry;
   177   LmMessageNode *node = cn->transport, *node2;
   177 
   178   const gchar *modestr;
   178   for (entry = local_ips; entry; entry = entry->next) {
   179 
   179     LocalIP *lcand = (LocalIP *)entry->data;
   180   js5b = g_new0(JingleS5B, 1);
       
   181   modestr    = lm_message_node_get_attribute(node, "mode");
       
   182   js5b->mode = index_in_array(modestr, jingle_s5b_modes);
       
   183   js5b->sid  = g_strdup(lm_message_node_get_attribute(node, "sid"));
       
   184 
       
   185   if (!js5b->sid) {
       
   186     g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
       
   187                 "an attribute of the transport element is missing");
       
   188     g_free(js5b);
       
   189     return NULL;
       
   190   }
       
   191 
       
   192   js5b->candidates = parse_candidates(node);
       
   193 
       
   194   return (gconstpointer) js5b;
       
   195 }
       
   196 
       
   197 static gconstpointer new(void)
       
   198 {
       
   199   JingleS5B *js5b = g_new0(JingleS5B, 1);
       
   200   GSList *entry;
       
   201   gint port;
       
   202 
       
   203   js5b->mode = JINGLE_S5B_TCP;
       
   204   js5b->sid  = gen_random_sid();
       
   205   port = settings_opt_get_int("jingle_s5b_dir");
       
   206   if (port < 1024 && port > (guint16)~0) {
       
   207     port = g_random_int_range(1024, (guint16)~0);
       
   208   }
       
   209 
       
   210   for (entry = local_candidates; entry; entry = entry->next) {
       
   211     LocalCandidate *lcand = (LocalCandidate *)entry->data;
       
   212     S5BCandidate *cand = g_new0(S5BCandidate, 1);
   180     S5BCandidate *cand = g_new0(S5BCandidate, 1);
   213     cand->cid      = gen_random_cid();
   181     cand->cid      = gen_random_cid();
   214     cand->host     = g_inet_address_to_string(lcand->address);
   182     cand->host     = g_inet_address_to_string(lcand->address);
   215     cand->jid      = g_strdup(lm_connection_get_jid(lconnection));
   183     cand->jid      = g_strdup(lm_connection_get_jid(lconnection));
   216     cand->port     = port;
   184     cand->port     = port;
   217     cand->priority = lcand->priority;
   185     cand->priority = lcand->priority;
   218 
   186 
   219     js5b->ourcandidates = g_slist_prepend(js5b->ourcandidates, cand);
   187     our_candidates = g_slist_prepend(our_candidates, cand);
   220   }
   188   }
       
   189   our_candidates = g_slist_sort(our_candidates, prioritycmp);
       
   190   return our_candidates;
       
   191 }
       
   192 
       
   193 /**
       
   194  * @brief Get a port number by settings or randomly
       
   195  * @return A guint16 containing the port number
       
   196  * */
       
   197 static guint16 get_port(void)
       
   198 {
       
   199   // TODO: find a way to make sure the port is not already used
       
   200   guint64 portstart, portend;
       
   201   guint16 port;
       
   202   const gchar *port_range = settings_opt_get("jingle_s5b_portrange");
       
   203 
       
   204   if (port_range != NULL) {
       
   205     sscanf(port_range, "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, &portstart, &portend);
       
   206 
       
   207     if ((portstart >= 1024 && portstart <= (guint16)~0) &&
       
   208         (portend >= 1024 && portend <= (guint16)~0) && portstart <= portend) {
       
   209       port = g_random_int_range(portstart, portend);
       
   210     } else {
       
   211       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Invalid port range specified");
       
   212       port = g_random_int_range(1024, (guint16)~0);
       
   213     }
       
   214   } else {
       
   215     port = g_random_int_range(1024, (guint16)~0);
       
   216   }
       
   217 
       
   218   return port;
       
   219 }
       
   220 
       
   221 static gconstpointer newfrommessage(JingleContent *cn, GError **err)
       
   222 {
       
   223   JingleS5B *js5b;
       
   224   LmMessageNode *node = cn->transport;
       
   225   const gchar *modestr;
       
   226 
       
   227   js5b = g_new0(JingleS5B, 1);
       
   228   modestr    = lm_message_node_get_attribute(node, "mode");
       
   229   js5b->mode = index_in_array(modestr, jingle_s5b_modes);
       
   230   js5b->sid  = g_strdup(lm_message_node_get_attribute(node, "sid"));
       
   231 
       
   232   if (!js5b->sid) {
       
   233     g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
       
   234                 "an attribute of the transport element is missing");
       
   235     g_free(js5b);
       
   236     return NULL;
       
   237   }
       
   238 
       
   239   js5b->candidates = parse_candidates(node);
       
   240   js5b->ourcandidates = get_our_candidates(get_port());
       
   241 
       
   242   return (gconstpointer) js5b;
       
   243 }
       
   244 
       
   245 static gconstpointer new(void)
       
   246 {
       
   247   JingleS5B *js5b = g_new0(JingleS5B, 1);
       
   248 
       
   249 
       
   250   js5b->mode = JINGLE_S5B_TCP;
       
   251   js5b->sid  = gen_random_sid();
       
   252   // the user can manually specify a port range to use in for format:
       
   253   // portstart-portend
       
   254 
       
   255 
       
   256   js5b->ourcandidates = get_our_candidates(get_port());
       
   257 
   221   return js5b;
   258   return js5b;
   222 }
   259 }
   223 
   260 
   224 static JingleHandleStatus
   261 static JingleHandleStatus
   225 handle_session_accept(JingleS5B *js5b, LmMessageNode *node, GError **err)
   262 handle_session_accept(JingleS5B *js5b, LmMessageNode *node, GError **err)
   336 
   373 
   337 /**
   374 /**
   338  * @brief Discover all IPs of this computer
   375  * @brief Discover all IPs of this computer
   339  * @return A linked list of GInetAddress
   376  * @return A linked list of GInetAddress
   340  */
   377  */
   341 static GSList *get_all_local_ips() {
   378 static GSList *get_all_local_ips(void) {
   342   GSList *addresses = NULL;
   379   GSList *addresses = NULL;
   343   GInetAddress *thisaddr;
   380   GInetAddress *thisaddr;
   344   GSocketFamily family;
   381   GSocketFamily family;
   345   struct ifaddrs *first, *ifaddr;
   382   struct ifaddrs *first, *ifaddr;
   346   struct sockaddr_in *native;
   383   struct sockaddr_in *native;
   347   struct sockaddr_in6 *native6;
   384   struct sockaddr_in6 *native6;
   348   const guint8 *addrdata;
   385   const guint8 *addrdata;
   349   guint16 ifacecounter = 0; // for lack of a better method
   386   guint16 ifacecounter = 0; // for lack of a better method
   350   LocalCandidate *candidate;
   387   LocalIP *candidate;
   351 
   388 
   352   gint rval = getifaddrs(&first);
   389   gint rval = getifaddrs(&first);
   353   if (!rval)
   390   if (!rval)
   354     return NULL;
   391     return NULL;
   355 
   392 
   373       g_object_unref(thisaddr);
   410       g_object_unref(thisaddr);
   374       continue;
   411       continue;
   375     }/* else if (g_inset_address_get_is_site_local(thisaddr)) {
   412     }/* else if (g_inset_address_get_is_site_local(thisaddr)) {
   376       // TODO: should we offer a way to filter the offer of LAN ips ?
   413       // TODO: should we offer a way to filter the offer of LAN ips ?
   377     } */
   414     } */
   378     candidate = g_new0(LocalCandidate, 1);
   415     candidate = g_new0(LocalIP, 1);
   379     candidate->address  = thisaddr;
   416     candidate->address  = thisaddr;
   380     candidate->priority = (1<<16)*126+ifacecounter;
   417     candidate->priority = (1<<16)*126+ifacecounter;
   381     addresses = g_slist_prepend(addresses, candidate);
   418     addresses = g_slist_prepend(addresses, candidate);
   382     ++ifacecounter;
   419     ++ifacecounter;
   383   }
   420   }
   407 static gchar *gen_random_cid(void)
   444 static gchar *gen_random_cid(void)
   408 {
   445 {
   409   return random_str(7);
   446   return random_str(7);
   410 }
   447 }
   411 
   448 
       
   449 static void free_localip(LocalIP *l) {
       
   450   g_object_unref(l->address);
       
   451   g_free(l);
       
   452 }
       
   453 
   412 static void jingle_socks5_init(void)
   454 static void jingle_socks5_init(void)
   413 {
   455 {
   414   g_type_init();
   456   g_type_init();
   415   jingle_register_transport(NS_JINGLE_TRANSPORT_SOCKS5, &funcs,
   457   jingle_register_transport(NS_JINGLE_TRANSPORT_SOCKS5, &funcs,
   416                             JINGLE_TRANSPORT_STREAMING,
   458                             JINGLE_TRANSPORT_STREAMING,
   417                             JINGLE_TRANSPORT_PRIO_HIGH);
   459                             JINGLE_TRANSPORT_PRIO_HIGH);
   418   xmpp_add_feature(NS_JINGLE_TRANSPORT_SOCKS5);
   460   xmpp_add_feature(NS_JINGLE_TRANSPORT_SOCKS5);
   419   local_candidates = get_all_local_ips();
   461   local_ips = get_all_local_ips();
   420 }
   462 }
   421 
   463 
   422 static void jingle_socks5_uninit(void)
   464 static void jingle_socks5_uninit(void)
   423 {
   465 {
   424   xmpp_del_feature(NS_JINGLE_TRANSPORT_SOCKS5);
   466   xmpp_del_feature(NS_JINGLE_TRANSPORT_SOCKS5);
   425   jingle_unregister_transport(NS_JINGLE_TRANSPORT_SOCKS5);
   467   jingle_unregister_transport(NS_JINGLE_TRANSPORT_SOCKS5);
   426   g_slist_foreach(local_candidates, (GFunc)g_object_unref, NULL);
   468   g_slist_foreach(local_ips, (GFunc)free_localip, NULL);
   427 }
   469   g_slist_free(local_ips);
       
   470 }