From: Alexandre Chataignon <alexandre.chataig...@mobirider.com> ---
This is Alexandre's original patch. I have only changed the title slightly. src/connman.h | 4 ++- src/dnsproxy.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/technology.c | 7 ++++- src/tethering.c | 22 ++++++++++++++-- 4 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/connman.h b/src/connman.h index 35eb3f5..7b3265f 100644 --- a/src/connman.h +++ b/src/connman.h @@ -619,7 +619,7 @@ int __connman_tethering_init(void); void __connman_tethering_cleanup(void); const char *__connman_tethering_get_bridge(void); -void __connman_tethering_set_enabled(void); +void __connman_tethering_set_enabled(bool captive_dns); void __connman_tethering_set_disabled(void); int __connman_private_network_request(DBusMessage *msg, const char *owner); @@ -930,6 +930,8 @@ int __connman_dnsproxy_add_listener(int index); void __connman_dnsproxy_remove_listener(int index); int __connman_dnsproxy_append(int index, const char *domain, const char *server); int __connman_dnsproxy_remove(int index, const char *domain, const char *server); +int __connman_dnsproxy_enable_captive(uint32_t ip) ; +int __connman_dnsproxy_disable_captive(void) ; int __connman_6to4_probe(struct connman_service *service); void __connman_6to4_remove(struct connman_ipconfig *ipconfig); diff --git a/src/dnsproxy.c b/src/dnsproxy.c index a1eda55..f72b5cc 100644 --- a/src/dnsproxy.c +++ b/src/dnsproxy.c @@ -76,6 +76,14 @@ struct domain_hdr { #else #error "Unknown byte order" #endif +struct a_dns_answer { + uint16_t ptr; + uint16_t type; + uint16_t class; + uint32_t ttl; + uint16_t rdlength; + uint32_t ip; +} __attribute__ ((packed)) ; struct partial_reply { uint16_t len; @@ -216,6 +224,7 @@ static GHashTable *listener_table = NULL; static time_t next_refresh; static GHashTable *partial_tcp_req_table; static guint cache_timer = 0; +static uint32_t captive_ip = 0; static guint16 get_id(void) { @@ -502,6 +511,58 @@ static void send_response(int sk, unsigned char *buf, int len, } } +static void send_response_A(int sk, unsigned char *req, int len, + uint32_t ip, + const struct sockaddr *to, socklen_t tolen, + int protocol) +{ + struct domain_hdr *hdr; + struct a_dns_answer* ans; + int err, offset = protocol_offset(protocol); + + DBG("sk %d", sk); + + if (offset < 0) + return; + + if (len < 12) + return; + + size_t new_len = len+sizeof(struct a_dns_answer) ; + char* new_buf ; + new_buf = g_malloc(new_len) ; + memcpy(new_buf, req, len) ; + + hdr = (void *) (new_buf + offset); + + DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode); + + hdr->qr = 1; + hdr->rcode = ns_r_noerror; + + hdr->ancount = htons(1); + hdr->nscount = 0; + hdr->arcount = 0; + + /* Create A answer */ + /* Other attributes */ + ans = (void *) (new_buf + len); + ans->ptr = htons(0xc00c) ;/* 11....1100 -> ptr to 12th octet = query */ + ans->type = htons(ns_t_a); + ans->class = htons(ns_c_in); + ans->ttl = 0; + ans->rdlength = htons(4); + ans->ip = htonl(ip); + + err = sendto(sk, new_buf, new_len, MSG_NOSIGNAL, to, tolen); + g_free(new_buf) ; + if (err < 0) { + connman_error("Failed to send DNS response to %d: %s", + sk, strerror(errno)); + return; + } +} + static int get_req_udp_socket(struct request_data *req) { GIOChannel *channel; @@ -3429,6 +3490,14 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition, DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8); + /* If captive mode, all is redirected to tether ip */ + if (captive_ip) { + send_response_A(sk, buf, len, + captive_ip, + client_addr, *client_addr_len, IPPROTO_UDP); + return true ; + } + err = parse_request(buf, len, query, sizeof(query)); if (err < 0 || (g_slist_length(server_list) == 0)) { send_response(sk, buf, len, client_addr, @@ -3885,3 +3954,13 @@ void __connman_dnsproxy_cleanup(void) g_hash_table_destroy(partial_tcp_req_table); } + +int __connman_dnsproxy_enable_captive(uint32_t ip) { + captive_ip = ip ; + return 0; +} + +int __connman_dnsproxy_disable_captive(void) { + captive_ip = 0 ; + return 0; +} diff --git a/src/technology.c b/src/technology.c index 55303a0..c6475b8 100644 --- a/src/technology.c +++ b/src/technology.c @@ -66,6 +66,7 @@ struct connman_technology { */ char *tethering_ident; char *tethering_passphrase; + bool tethering_captive; bool enable_persistent; /* Save the tech state */ @@ -224,7 +225,7 @@ void connman_technology_tethering_notify(struct connman_technology *technology, tethering_changed(technology); if (enabled) - __connman_tethering_set_enabled(); + __connman_tethering_set_enabled(technology->tethering_captive); else __connman_tethering_set_disabled(); } @@ -428,6 +429,10 @@ static void technology_load(struct connman_technology *technology) technology->tethering_passphrase = g_key_file_get_string(keyfile, identifier, "Tethering.Passphrase", NULL); + + technology->tethering_captive = g_key_file_get_boolean(keyfile, + identifier, "Tethering.Captive", false); + done: g_free(identifier); diff --git a/src/tethering.c b/src/tethering.c index ceeec74..9187178 100644 --- a/src/tethering.c +++ b/src/tethering.c @@ -56,6 +56,7 @@ static char *private_network_primary_dns = NULL; static char *private_network_secondary_dns = NULL; static volatile int tethering_enabled; +static volatile bool captive_enabled; static GDHCPServer *tethering_dhcp_server = NULL; static struct connman_ippool *dhcp_ippool = NULL; static DBusConnection *connection; @@ -178,10 +179,10 @@ static void tethering_restart(struct connman_ippool *pool, void *user_data) { DBG("pool %p", pool); __connman_tethering_set_disabled(); - __connman_tethering_set_enabled(); + __connman_tethering_set_enabled(captive_enabled); } -void __connman_tethering_set_enabled(void) +void __connman_tethering_set_enabled(bool captive_dns) { int index; int err; @@ -193,6 +194,7 @@ void __connman_tethering_set_enabled(void) const char *dns; unsigned char prefixlen; char **ns; + captive_enabled = captive_dns; DBG("enabled %d", tethering_enabled + 1); @@ -279,6 +281,19 @@ void __connman_tethering_set_enabled(void) return; } + if (captive_dns) { + err = __connman_dnsproxy_enable_captive(htonl(inet_addr(gateway))); + if (err < 0) { + connman_error("Cannot enable captive DNS"); + dhcp_server_stop(tethering_dhcp_server); + __connman_bridge_disable(BRIDGE_NAME); + __connman_ippool_unref(dhcp_ippool); + __connman_bridge_remove(BRIDGE_NAME); + __sync_fetch_and_sub(&tethering_enabled, 1); + return; + } + } + err = __connman_ipv6pd_setup(BRIDGE_NAME); if (err < 0 && err != -EINPROGRESS) DBG("Cannot setup IPv6 prefix delegation %d/%s", err, @@ -302,6 +317,7 @@ void __connman_tethering_set_disabled(void) __connman_dnsproxy_remove_listener(index); __connman_nat_disable(BRIDGE_NAME); + __connman_dnsproxy_disable_captive(); dhcp_server_stop(tethering_dhcp_server); @@ -398,6 +414,7 @@ static void remove_private_network(gpointer user_data) __connman_nat_disable(BRIDGE_NAME); connman_rtnl_remove_watch(pn->iface_watch); __connman_ippool_unref(pn->pool); + __connman_dnsproxy_disable_captive(); if (pn->watch > 0) { g_dbus_remove_watch(connection, pn->watch); @@ -548,6 +565,7 @@ void __connman_tethering_cleanup(void) __connman_bridge_disable(BRIDGE_NAME); __connman_bridge_remove(BRIDGE_NAME); __connman_nat_disable(BRIDGE_NAME); + __connman_dnsproxy_disable_captive(); } if (!connection) -- 2.1.4 _______________________________________________ connman mailing list connman@connman.net https://lists.connman.net/mailman/listinfo/connman