jingle-s5b/socks5.c
changeset 164 6866328b34bd
parent 163 a4c75fe75869
child 165 763c26abd99d
equal deleted inserted replaced
163:a4c75fe75869 164:6866328b34bd
    46 static gconstpointer newfrommessage(JingleContent *cn, GError **err);
    46 static gconstpointer newfrommessage(JingleContent *cn, GError **err);
    47 static JingleHandleStatus handle(JingleAction action, gconstpointer data,
    47 static JingleHandleStatus handle(JingleAction action, gconstpointer data,
    48                                  LmMessageNode *node, GError **err);
    48                                  LmMessageNode *node, GError **err);
    49 static void tomessage(gconstpointer data, LmMessageNode *node);
    49 static void tomessage(gconstpointer data, LmMessageNode *node);
    50 static gconstpointer new(void);
    50 static gconstpointer new(void);
    51 // static void _send(session_content *sc, gconstpointer data, gchar *buf, gsize size);
    51 static void _send(session_content *sc, gconstpointer data, gchar *buf, gsize size);
    52 static void init(session_content *sc, gconstpointer data);
    52 static void init(session_content *sc, gconstpointer data);
    53 static void end(session_content *sc, gconstpointer data);
    53 static void end(session_content *sc, gconstpointer data);
    54 static gchar *info(gconstpointer data);
    54 static gchar *info(gconstpointer data);
    55 
    55 
       
    56 static void connect_candidate(JingleS5B *js5b, S5BCandidate *cand);
       
    57 static void connect_next_candidate(JingleS5B *js5b, S5BCandidate *cand);
    56 static void
    58 static void
    57 handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer userdata);
    59 handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer data);
       
    60 static void
       
    61 handle_client_connect(GObject *_client, GAsyncResult *res, gpointer data);
    58 static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data);
    62 static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data);
    59 static GSList *get_all_local_ips();
    63 static GSList *get_all_local_ips();
    60 static gchar *gen_random_sid(void);
    64 static gchar *gen_random_sid(void);
    61 static gchar *gen_random_cid(void);
    65 static gchar *gen_random_cid(void);
    62 static void jingle_socks5_init(void);
    66 static void jingle_socks5_init(void);
    68 static JingleTransportFuncs funcs = {
    72 static JingleTransportFuncs funcs = {
    69   .newfrommessage = newfrommessage,
    73   .newfrommessage = newfrommessage,
    70   .handle         = handle,
    74   .handle         = handle,
    71   .tomessage      = tomessage,
    75   .tomessage      = tomessage,
    72   .new            = new,
    76   .new            = new,
    73   .send           = NULL,
    77   .send           = _send,
    74   .init           = init,
    78   .init           = init,
    75   .end            = end,
    79   .end            = end,
    76   .info           = info
    80   .info           = info
    77 };
    81 };
    78 
    82 
   203 static guint16 get_port(void)
   207 static guint16 get_port(void)
   204 {
   208 {
   205   // TODO: find a way to make sure the port is not already used
   209   // TODO: find a way to make sure the port is not already used
   206   guint64 portstart, portend;
   210   guint64 portstart, portend;
   207   guint16 port;
   211   guint16 port;
   208   const gchar *port_range = settings_opt_get("jingle_s5b_portrange");
   212   const gchar *port_range = settings_opt_get("js5b_portrange");
   209 
   213 
   210   if (port_range != NULL) {
   214   if (port_range != NULL) {
   211     sscanf(port_range, "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, &portstart, &portend);
   215     sscanf(port_range, "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, &portstart, &portend);
   212 
   216 
   213     if ((portstart >= 1024 && portstart <= (guint16)~0) &&
   217     if ((portstart >= 1024 && portstart <= (guint16)~0) &&
   318 
   322 
   319 static void init(session_content *sc, gconstpointer data)
   323 static void init(session_content *sc, gconstpointer data)
   320 {
   324 {
   321   JingleS5B *js5b = (JingleS5B *)data;
   325   JingleS5B *js5b = (JingleS5B *)data;
   322   GSocketAddress *saddr;
   326   GSocketAddress *saddr;
   323   //GSource *socksource;
       
   324   guint numlistening = 0; // number of addresses we are listening to
   327   guint numlistening = 0; // number of addresses we are listening to
   325   GSList *entry;
   328   GSList *entry;
   326   GError *err = NULL;
   329   GError *err = NULL;
       
   330   GSocket *sock;
   327 
   331 
   328   // First, we listen on all ips
   332   // First, we listen on all ips
   329   js5b->listener = g_socket_listener_new();
   333   js5b->listener = g_socket_listener_new();
   330   for (entry = js5b->ourcandidates; entry; entry = entry->next) {
   334   for (entry = js5b->ourcandidates; entry; entry = entry->next) {
   331     S5BCandidate *cand = (S5BCandidate *)entry->data;
   335     S5BCandidate *cand = (S5BCandidate *)entry->data;
   332 
   336 
   333     cand->sock = g_socket_new(g_inet_address_get_family(cand->host),
   337     sock = g_socket_new(g_inet_address_get_family(cand->host),
   334                               G_SOCKET_TYPE_STREAM,
   338                         G_SOCKET_TYPE_STREAM,
   335                               G_SOCKET_PROTOCOL_TCP, &err);
   339                         G_SOCKET_PROTOCOL_TCP, &err);
   336     if (cand->sock == NULL) {
   340     if (sock == NULL) {
   337       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Error while creating a new socket: %s",
   341       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Error while creating a new socket: %s",
   338                    err->message != NULL ? err->message : "(no message)");
   342                    err->message ? err->message : "(no message)");
   339       continue;
   343       continue;
   340     }
   344     }
   341     g_socket_set_blocking(cand->sock, FALSE);
   345     g_socket_set_blocking(sock, FALSE);
   342 
   346 
   343     saddr = g_inet_socket_address_new(cand->host, cand->port);
   347     saddr = g_inet_socket_address_new(cand->host, cand->port);
   344     if (!g_socket_bind(cand->sock, saddr, TRUE, &err)) {
   348     if (!g_socket_bind(sock, saddr, TRUE, &err)) {
   345       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to bind a socket on %s port %u: %s",
   349       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to bind a socket on %s port %u: %s",
   346                    g_inet_address_to_string(cand->host),
   350                    g_inet_address_to_string(cand->host),
   347                    cand->port,
   351                    cand->port,
   348                    err->message != NULL ? err->message : "(no message)");
   352                    err->message ? err->message : "(no message)");
   349       goto cleancontinue;
   353       goto cleancontinue;
   350     }
   354     }
   351 
   355 
   352     if (!g_socket_listen(cand->sock, &err)) {
   356     if (!g_socket_listen(sock, &err)) {
   353       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to listen on %s port %u: %s",
   357       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to listen on %s port %u: %s",
   354                    g_inet_address_to_string(cand->host),
   358                    g_inet_address_to_string(cand->host),
   355                    cand->port,
   359                    cand->port,
   356                    err->message != NULL ? err->message : "(no message)");
   360                    err->message ? err->message : "(no message)");
   357       goto cleancontinue;
   361       goto cleancontinue;
   358     }
   362     }
   359 
   363 
   360     if (!g_socket_listener_add_socket(js5b->listener, cand->sock, NULL, &err)) {
   364     if (!g_socket_listener_add_socket(js5b->listener, sock, NULL, &err)) {
   361       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to add our socket to the"
   365       scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to add our socket to the"
   362                    " GSocketListener: %s",
   366                    " GSocketListener: %s",
   363                    err->message != NULL ? err->message : "(no message)");
   367                    err->message ? err->message : "(no message)");
   364       goto cleancontinue;
   368       goto cleancontinue;
   365 	}
   369 	}
   366 
   370 
   367     scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Listening on %s:%u",
   371     scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Listening on %s:%u",
   368                  g_inet_address_to_string(cand->host),
   372                  g_inet_address_to_string(cand->host),
   369                  cand->port);
   373                  cand->port);
   370 	++numlistening;
   374 	++numlistening;
   371 
   375 
   372 cleancontinue:
   376 cleancontinue:
       
   377       if (err != NULL) g_clear_error(&err);
   373       g_object_unref(saddr);
   378       g_object_unref(saddr);
   374       g_object_unref(cand->sock);
   379       g_object_unref(sock);
   375   }
   380   }
   376 
   381 
   377   if (numlistening > 0) {
   382   if (numlistening > 0) {
   378     g_socket_listener_accept_async(js5b->listener, NULL, handle_listener_accept, NULL);
   383     g_socket_listener_accept_async(js5b->listener, NULL, handle_listener_accept, NULL);
   379   } else {
   384   } else {
   380       g_object_unref(js5b->listener);
   385       g_object_unref(js5b->listener);
   381   }
   386   }
   382 
   387 
   383   // Then, we start connecting to the other entity's candidates, if any.
   388   // Then, we start connecting to the other entity's candidates, if any.
       
   389   if (js5b->candidates) {
       
   390     js5b->client = g_socket_client_new();
       
   391     S5BCandidate *cand = (S5BCandidate *)js5b->candidates->data;
       
   392     connect_candidate(js5b, cand);
       
   393   }
       
   394 }
       
   395 
       
   396 /**
       
   397  * @brief Cancel an ongoing connection after 5 seconds
       
   398  * @param data  A GPtrArray
       
   399  * 
       
   400  * "A client SHOULD NOT wait for a TCP timeout on connect.
       
   401  * If it is unable to connect to any candidate within 5 seconds
       
   402  * it SHOULD send a candidate-error to the other party."
       
   403  */
       
   404 static gboolean connect_cancel_timeout(gpointer data)
       
   405 {
       
   406   GPtrArray *args = (GPtrArray *)data;
       
   407   JingleS5B *js5b = g_ptr_array_index(args, 0);
       
   408   //S5BCandidate *cand = g_ptr_array_index(args, 1);
       
   409   g_ptr_array_unref(args);
       
   410 
       
   411   g_cancellable_cancel(js5b->cancelconnect);
       
   412   return FALSE;
       
   413 }
       
   414 
       
   415 static void connect_candidate(JingleS5B *js5b, S5BCandidate *cand)
       
   416 {
       
   417   GSocketAddress *saddr;
       
   418   GPtrArray *args;
       
   419   guint eventid;
       
   420 
       
   421   args = g_ptr_array_sized_new(2);
       
   422   g_ptr_array_add(args, js5b);
       
   423   g_ptr_array_add(args, cand);
       
   424 
       
   425   saddr = g_inet_socket_address_new(cand->host, cand->port);
       
   426   js5b->cancelconnect = g_cancellable_new();
       
   427 
       
   428   eventid = g_timeout_add_seconds(5, connect_cancel_timeout, g_ptr_array_ref(args));
       
   429   g_ptr_array_add(args, GUINT_TO_POINTER(eventid));
       
   430   g_socket_client_connect_async(js5b->client, G_SOCKET_CONNECTABLE(saddr),
       
   431                                 js5b->cancelconnect, handle_client_connect, args);
       
   432   g_object_unref(saddr);
       
   433 }
       
   434 
       
   435 /**
       
   436  * Convenience function that find the next candidate to try and
       
   437  * call connect_candidate
       
   438  */
       
   439 static void connect_next_candidate(JingleS5B *js5b, S5BCandidate *cand)
       
   440 {
       
   441   GSList *link = g_slist_find(js5b->candidates, cand);
       
   442   if (js5b->cancelconnect != NULL)
       
   443     g_object_unref(js5b->cancelconnect);
       
   444   g_assert(link != NULL);
       
   445   if (link->next == NULL) {
       
   446     // there is no next candidate to try.
       
   447   }
       
   448   connect_candidate(js5b, (S5BCandidate *)link->next->data);
       
   449   return;
   384 }
   450 }
   385 
   451 
   386 static gchar *info(gconstpointer data)
   452 static gchar *info(gconstpointer data)
   387 {
   453 {
   388   //JingleS5B *js5b = (JingleS5B *)data;
   454   //JingleS5B *js5b = (JingleS5B *)data;
   392 
   458 
   393 static void end(session_content *sc, gconstpointer data) {
   459 static void end(session_content *sc, gconstpointer data) {
   394   return;
   460   return;
   395 }
   461 }
   396 
   462 
   397 
       
   398 /**
   463 /**
   399  * @brief Handle incoming connections
   464  * @brief Handle incoming connections
   400  */
   465  */
   401 static void
   466 static void
   402 handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer userdata)
   467 handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer data)
   403 {
   468 {
   404   GError *err = NULL;
   469   GError *err = NULL;
   405   GSocketConnection *conn;
   470   GSocketConnection *conn;
   406   conn = g_socket_listener_accept_finish((GSocketListener *) _listener, res, NULL, &err);
   471   //scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Got Incoming Connection");
       
   472   conn = g_socket_listener_accept_finish(G_SOCKET_LISTENER(_listener), res, NULL, &err);
       
   473 }
       
   474 
       
   475 /**
       
   476  * @brief Handle outgoing connections
       
   477  */
       
   478 static void
       
   479 handle_client_connect(GObject *_client, GAsyncResult *res, gpointer data)
       
   480 {
       
   481   GError *err = NULL;
       
   482   GSocketConnection *conn;
       
   483   GPtrArray *args;
       
   484   JingleS5B *js5b;
       
   485   S5BCandidate *cand;
       
   486   //scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Got Outgoing Connection");
       
   487   
       
   488   args = (GPtrArray *)data;
       
   489   js5b = g_ptr_array_index(args, 0);
       
   490   cand = g_ptr_array_index(args, 1);
       
   491   g_ptr_array_unref(args);
       
   492 
       
   493   conn = g_socket_client_connect_finish(G_SOCKET_CLIENT(_client), res, &err);
       
   494 
       
   495   if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
       
   496     // if we did not received a CANCELLED error, then the time limit was not
       
   497     // reached and we need to clean up the GSource and unref args a second time.
       
   498     guint eventid = GPOINTER_TO_UINT(g_ptr_array_index(args, 2));
       
   499     GSource *s = g_main_context_find_source_by_id(NULL, eventid);
       
   500     g_source_destroy(s);
       
   501     g_ptr_array_unref(args);
       
   502     connect_next_candidate(js5b, cand);
       
   503     // we need to send a candidate-error in case we cannot connect.
       
   504     return;
       
   505   }
       
   506 
       
   507   if (err != NULL) {
       
   508     if (err->domain == G_IO_ERROR)
       
   509       scr_LogPrint(LPRINT_DEBUG, "Jingle S5B: IO Error (%s)",
       
   510                    err->message ? err->message : "no message");
       
   511     else
       
   512       scr_LogPrint(LPRINT_DEBUG, "Jingle S5B: %s Error (%s)",
       
   513                    g_quark_to_string (err->domain),
       
   514                    err->message ? err->message : "no message");
       
   515 
       
   516     g_error_free(err);
       
   517     connect_next_candidate(js5b, cand);
       
   518     return;
       
   519   }
       
   520   js5b->connection = conn;
       
   521   // we have a valid connection
   407 }
   522 }
   408 
   523 
   409 /**
   524 /**
   410  * @brief Handle any event on a sock
   525  * @brief Handle any event on a sock
   411  */
   526  */
   424       ;
   539       ;
   425       // ?!
   540       // ?!
   426   }
   541   }
   427 }
   542 }
   428 
   543 
       
   544 static void _send(session_content *sc, gconstpointer data, gchar *buf, gsize size)
       
   545 {
       
   546   return;
       
   547 }
       
   548 
   429 /**
   549 /**
   430  * @brief Discover all IPs of this computer
   550  * @brief Discover all IPs of this computer
   431  * @return A linked list of GInetAddress
   551  * @return A linked list of GInetAddress
   432  */
   552  */
   433 static GSList *get_all_local_ips(void) {
   553 static GSList *get_all_local_ips(void) {
   438   struct sockaddr_in *native;
   558   struct sockaddr_in *native;
   439   struct sockaddr_in6 *native6;
   559   struct sockaddr_in6 *native6;
   440   const guint8 *addrdata;
   560   const guint8 *addrdata;
   441   guint16 ifacecounter = 0; // for lack of a better method
   561   guint16 ifacecounter = 0; // for lack of a better method
   442   LocalIP *candidate;
   562   LocalIP *candidate;
       
   563   gchar **ifblacklist;
       
   564   guint ifblkcnt;
   443 
   565 
   444   gint rval = getifaddrs(&first);
   566   gint rval = getifaddrs(&first);
   445   if (rval != 0)
   567   if (rval != 0) {
       
   568     scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to retreive local ip addresses");
   446     return NULL;
   569     return NULL;
       
   570   }
       
   571 
       
   572   if (settings_opt_get("js5b_iface_blacklist") != NULL) {
       
   573     ifblacklist = g_strsplit(settings_opt_get("js5b_iface_blacklist"), ",", 0);
       
   574   } else {
       
   575     ifblacklist = (gchar*[]){NULL};
       
   576   }
   447 
   577 
   448   for (ifaddr = first; ifaddr; ifaddr = ifaddr->ifa_next) {
   578   for (ifaddr = first; ifaddr; ifaddr = ifaddr->ifa_next) {
       
   579     gboolean continueloop = FALSE;
   449     if (!(ifaddr->ifa_flags & IFF_UP) || ifaddr->ifa_flags & IFF_LOOPBACK)
   580     if (!(ifaddr->ifa_flags & IFF_UP) || ifaddr->ifa_flags & IFF_LOOPBACK)
   450       continue;
   581       continue;
       
   582 
       
   583     for (ifblkcnt = 0; ifblacklist[ifblkcnt]; ifblkcnt++)
       
   584       if (!g_strcmp0(ifaddr->ifa_name, ifblacklist[ifblkcnt])) {
       
   585         continueloop = TRUE;
       
   586         break;
       
   587       }
       
   588     
       
   589     if (continueloop) continue;
   451 
   590 
   452     if (ifaddr->ifa_addr->sa_family == AF_INET) {
   591     if (ifaddr->ifa_addr->sa_family == AF_INET) {
   453       native = (struct sockaddr_in *)ifaddr->ifa_addr;
   592       native = (struct sockaddr_in *)ifaddr->ifa_addr;
   454       addrdata = (const guint8 *)&native->sin_addr.s_addr;
   593       addrdata = (const guint8 *)&native->sin_addr.s_addr;
   455       family = G_SOCKET_FAMILY_IPV4;
   594       family = G_SOCKET_FAMILY_IPV4;