#include #include "gateway-bindings.h" /* The main loop, exposed so we can quit it later */ static GMainLoop *main_loop; /* External port to forward from, and internal port to forward too */ static unsigned int internal_port = 0, external_port = 0; /* Host to forward to, and a description */ static char *internal_host = NULL, *desc = NULL; /* * Called when a gateway device is found on the network. This creates the port * forward and quits. */ static void service_proxy_available_cb (GUPnPControlPoint *cp, GUPnPServiceProxy *proxy) { GError *error = NULL; /* Delete any existing port mapping as some routers won't overwrite existing port mappings */ if (!DeletePortMapping (proxy, "", external_port, "TCP", &error)) /* 714 == NoSuchEntryInArray, so ignore this */ if (error->domain != GUPNP_CONTROL_ERROR || error->code != 714) g_error (error->message); /* Create the new port mapping */ if (!AddPortMapping (proxy, "", external_port, "TCP", internal_port, internal_host, TRUE, desc, 0, &error)) g_error (error->message); /* Done, so quit the main loop */ g_main_loop_quit (main_loop); } /* * Called after 5 seconds, which means that service_proxy_available_cb hasn't * been called. Either the network is broken or there is no UPnP capable * router, so quit. */ static gboolean timeout_cb (gpointer data) { g_printerr ("Cannot find a UPnP router\n"); g_main_loop_quit (main_loop); return FALSE; } int main (int argc, char **argv) { GOptionEntry entries[] = { { "external", 'e', 0, G_OPTION_ARG_INT, &external_port, "Port on the router to forward from", "PORT" }, { "internal", 'i', 0, G_OPTION_ARG_INT, &internal_port, "Port on the host to forward to", "PORT" }, { "host", 'h', 0, G_OPTION_ARG_STRING, &internal_host, "Optional host to forward to (default: this host)", "HOST" }, { "description", 'd', 0, G_OPTION_ARG_STRING, &desc, "Optional description", "DESC" }, { NULL } }; GError *error = NULL; GOptionContext *options; GUPnPContext *context; GUPnPControlPoint *cp; /* Initialize threads (needed by libsoup) and GType */ g_thread_init (NULL); g_type_init (); /* Parse the options */ options = g_option_context_new ("- add a port mapping to a UPnP router"); g_option_context_add_main_entries (options, entries, NULL); if (!g_option_context_parse (options, &argc, &argv, &error)) { g_print ("%s\n\n", error->message); g_print (g_option_context_get_help (options, TRUE, NULL)); return 1; } /* * We need the ports to be specified. We can use the local host if the * internal host isn't specified, and the description is optional. */ if (internal_port == 0 || external_port == 0) { g_print (g_option_context_get_help (options, TRUE, NULL)); return 1; } g_option_context_free (options); /* Create the UPnP context */ context = gupnp_context_new (NULL, NULL, 0, &error); if (error) { g_error (error->message); g_error_free (error); return 1; } /* If there was no internal host specified, use the GUPnP host IP */ if (internal_host == NULL) internal_host = g_strdup (gupnp_context_get_host_ip (context)); /* * Create the local UPnP control point, and search for WANIPConnection * services. */ cp = gupnp_control_point_new (context, "urn:schemas-upnp-org:service:WANIPConnection:1"); /* Connect up the announcement of service discovery */ g_signal_connect (cp, "service-proxy-available", G_CALLBACK (service_proxy_available_cb), NULL); /* Start the searching for the service */ gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE); /* Timeout in case we can't find a router */ g_timeout_add (5000, timeout_cb, NULL); /* * Create and enter the main loop. We'll leave it after creating a new port * mapping, or after five seconds. */ main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (main_loop); /* Cleanup */ g_main_loop_unref (main_loop); g_object_unref (cp); g_object_unref (context); g_free (internal_host); g_free (desc); return 0; }