aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Christian Hesse <mail@eworm.de>2017-04-29 21:50:26 +0200
committerGravatar Christian Hesse <mail@eworm.de>2017-04-29 23:05:35 +0200
commit0429aca36e7161e601df164b5c11e020942ebc8a (patch)
treebb65f899b3459bcc537db823400014ac23f0a586
parent94940d5e121ee8b93d4f94b81ba4bae98b8a5e26 (diff)
downloadpacredir-0429aca36e7161e601df164b5c11e020942ebc8a.tar.gz
pacredir-0429aca36e7161e601df164b5c11e020942ebc8a.tar.zst
Do not rely on mDNS...
... but do resolve the addresses within pacredir. The biggest advantage is that we do no longer require nss-mdns, which tends to fool us in different ways. As requests are done by address rather than host name you can no longer use virtual hosts for pacserve and pacdbserve. But did anybody try that?
-rw-r--r--README.md11
-rw-r--r--pacredir.c94
-rw-r--r--pacredir.h24
3 files changed, 96 insertions, 33 deletions
diff --git a/README.md b/README.md
index 6f27df9..182866e 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ downloads its package files from online mirrors, transferring all the
bits via WAN connection.
But often other Arch systems may be around that already have the files
-available on local storage - just a fast LAN connection way. This is
+available on local storage - just a fast LAN connection away. This is
where `pacredir` can help. It uses [Avahi](http://avahi.org/) to find
other instances and get the files there if available.
@@ -23,7 +23,6 @@ To compile and run `pacredir` you need:
* [curl](http://curl.haxx.se/)
* [iniparser](http://ndevilla.free.fr/iniparser/)
* [darkhttpd](http://dmr.ath.cx/net/darkhttpd/)
-* [nss-mdns](http://0pointer.de/lennart/projects/nss-mdns/)
* [markdown](http://daringfireball.net/projects/markdown/) (HTML documentation)
`Arch Linux` installs development files for the packages by default, so
@@ -49,11 +48,9 @@ Additionally systemd service files are installed to
Usage
-----
-Make sure [multicast-
-DNS](https://wiki.archlinux.org/index.php/Avahi#Hostname_resolution)
-works. Then enable systemd services `pacserve`, `pacdbserve` and
-`pacredir`, open TCP ports 7078 and 7079 and add the following line to
-your repository definitions in `pacman.conf`:
+Enable systemd services `pacserve`, `pacdbserve` and `pacredir`, open TCP
+ports `7078` and `7079` and add the following line to your repository
+definitions in `pacman.conf`:
> Include = /etc/pacman.d/pacredir
diff --git a/pacredir.c b/pacredir.c
index 60fca60..9325d74 100644
--- a/pacredir.c
+++ b/pacredir.c
@@ -46,21 +46,23 @@ char * get_fqdn(const char * hostname, const char * domainname) {
}
/*** get_url ***/
-char * get_url(const char * hostname, const uint16_t port, const char * uri) {
+char * get_url(const char * hostname, const char * address, const uint16_t port, const char * uri) {
+ const char * host;
char * url;
+ host = (*address ? address : hostname);
+
url = malloc(10 /* static chars of an url & null char */
- + strlen(hostname)
+ + strlen(host)
+ 5 /* max strlen of decimal 16bit value */
+ strlen(uri));
- sprintf(url, "http://%s:%d/%s",
- hostname, port, uri);
+ sprintf(url, "http://%s:%d/%s", host, port, uri);
return url;
}
/*** add_host ***/
-int add_host(const char * host, const uint16_t port, const char * type) {
+int add_host(const char * host, const char * address, const uint16_t port, const char * type) {
struct hosts * tmphosts = hosts;
struct request request;
@@ -79,6 +81,7 @@ int add_host(const char * host, const uint16_t port, const char * type) {
if (verbose > 0)
write_log(stdout, "Adding host %s with service %s (port %d)\n",
host, type, port);
+
tmphosts->host = strdup(host);
tmphosts->pacserve.port = 0;
@@ -96,6 +99,11 @@ int add_host(const char * host, const uint16_t port, const char * type) {
tmphosts->next->next = NULL;
update:
+ if (address != NULL)
+ memcpy(tmphosts->address, address, AVAHI_ADDRESS_STR_MAX);
+ else
+ memset(tmphosts->address, 0, AVAHI_ADDRESS_STR_MAX);
+
if (strcmp(type, PACSERVE) == 0) {
tmphosts->pacserve.online = 1;
tmphosts->pacserve.port = port;
@@ -108,7 +116,7 @@ update:
/* do a first request and let get_http_code() set the bad status */
request.host = tmphosts->host;
- request.url = get_url(request.host, request.service->port, "");
+ request.url = get_url(request.host, tmphosts->address, request.service->port, "");
request.http_code = 0;
request.last_modified = 0;
get_http_code(&request);
@@ -139,6 +147,48 @@ int remove_host(const char * host, const char * type) {
return EXIT_SUCCESS;
}
+/*** resolve_callback ***
+ * Called whenever a service has been resolved successfully or timed out */
+static void resolve_callback(AvahiServiceResolver *r,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiResolverEvent event,
+ const char *name,
+ const char *type,
+ const char *domain,
+ const char *host,
+ const AvahiAddress *address,
+ uint16_t port,
+ AvahiStringList *txt,
+ AvahiLookupResultFlags flags,
+ void* userdata) {
+ char ipaddress[AVAHI_ADDRESS_STR_MAX];
+ char intname[IFNAMSIZ];
+
+ assert(r);
+
+ if_indextoname(interface, intname);
+
+ switch (event) {
+ case AVAHI_RESOLVER_FAILURE:
+ write_log(stderr, "Failed to resolve service '%s' of type '%s' in domain '%s': %s\n",
+ name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
+ break;
+
+ case AVAHI_RESOLVER_FOUND:
+ avahi_address_snprint(ipaddress, AVAHI_ADDRESS_STR_MAX, address);
+
+ if (verbose > 0)
+ write_log(stdout, "Found service %s on host %s (%s) on interface %s\n",
+ type, host, ipaddress, intname);
+
+ add_host(host, ipaddress, strcmp(type, PACSERVE) == 0 ? PORT_PACSERVE : PORT_PACDBSERVE, type);
+ break;
+ }
+
+ avahi_service_resolver_free(r);
+}
+
/*** browse_callback ***
* Called whenever a new services becomes available on the LAN or is removed from the LAN */
static void browse_callback(AvahiServiceBrowser *b,
@@ -148,18 +198,21 @@ static void browse_callback(AvahiServiceBrowser *b,
const char *name,
const char *type,
const char *domain,
- AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
+ AvahiLookupResultFlags flags,
void* userdata) {
char * host;
char intname[IFNAMSIZ];
struct ignore_interfaces * tmp_ignore_interfaces = ignore_interfaces;
+ AvahiClient * c;
assert(b);
+ c = userdata;
+ if_indextoname(interface, intname);
+
switch (event) {
case AVAHI_BROWSER_FAILURE:
-
- write_log(stderr, "%s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
+ write_log(stderr, "Failed to browse: %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
avahi_simple_poll_quit(simple_poll);
return;
@@ -170,7 +223,6 @@ static void browse_callback(AvahiServiceBrowser *b,
goto out;
/* check whether to ignore the interface */
- if_indextoname(interface, intname);
while (tmp_ignore_interfaces->next != NULL) {
if (strcmp(intname, tmp_ignore_interfaces->interface) == 0) {
if (verbose > 0)
@@ -181,11 +233,9 @@ static void browse_callback(AvahiServiceBrowser *b,
tmp_ignore_interfaces = tmp_ignore_interfaces->next;
}
- if (verbose > 0)
- write_log(stdout, "Found service %s on host %s on interface %s\n",
- type, host, intname);
-
- add_host(host, strcmp(type, PACSERVE) == 0 ? PORT_PACSERVE : PORT_PACDBSERVE, type);
+ if ((avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_INET, 0, resolve_callback, c)) == NULL)
+ write_log(stderr, "Failed to create resolver for service '%s' of type '%s' in domain '%s': %s\n",
+ name, type, domain, avahi_strerror(avahi_client_errno(c)));
out:
free(host);
@@ -213,7 +263,7 @@ out:
/*** client_callback ***/
static void client_callback(AvahiClient *c,
AvahiClientState state,
- AVAHI_GCC_UNUSED void * userdata) {
+ void * userdata) {
assert(c);
if (state == AVAHI_CLIENT_FAILURE) {
@@ -431,12 +481,12 @@ static int ahc_echo(void * cls,
request->service = &(tmphosts->pacdbserve);
else
request->service = &(tmphosts->pacserve);
- request->url = get_url(tmphosts->host, request->service->port, basename);
+ request->url = get_url(tmphosts->host, tmphosts->address, request->service->port, basename);
request->http_code = 0;
request->last_modified = 0;
if (verbose > 0)
- write_log(stdout, "Trying: %s\n", request->url);
+ write_log(stdout, "Trying %s: %s\n", request->host, request->url);
if ((error = pthread_create(&tid[req_count], NULL, get_http_code, (void *)request)) != 0)
write_log(stderr, "Could not run thread number %d, errno %d\n", req_count, error);
@@ -648,7 +698,7 @@ int main(int argc, char ** argv) {
*strchr(value, ':') = 0;
} else
port = PORT_PACSERVE;
- add_host(value, port, PACSERVE);
+ add_host(value, NULL, port, PACSERVE);
value = strtok(NULL, DELIMITER);
}
free(values);
@@ -667,7 +717,7 @@ int main(int argc, char ** argv) {
*strchr(value, ':') = 0;
} else
port = PORT_PACDBSERVE;
- add_host(value, port, PACDBSERVE);
+ add_host(value, NULL, port, PACDBSERVE);
value = strtok(NULL, DELIMITER);
}
free(values);
@@ -690,13 +740,13 @@ int main(int argc, char ** argv) {
}
/* create the service browser for PACSERVE */
- if ((pacserve = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, PACSERVE, NULL, 0, browse_callback, NULL)) == NULL) {
+ if ((pacserve = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, PACSERVE, NULL, 0, browse_callback, client)) == NULL) {
write_log(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
goto fail;
}
/* create the service browser for PACDBSERVE */
- if ((pacdbserve = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, PACDBSERVE, NULL, 0, browse_callback, NULL)) == NULL) {
+ if ((pacdbserve = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, PACDBSERVE, NULL, 0, browse_callback, client)) == NULL) {
write_log(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
goto fail;
}
diff --git a/pacredir.h b/pacredir.h
index 161845e..2cd8cca 100644
--- a/pacredir.h
+++ b/pacredir.h
@@ -61,6 +61,8 @@ struct services {
struct hosts {
/* host name */
char * host;
+ /* resolved address */
+ char address[AVAHI_ADDRESS_STR_MAX];
/* online status and bad time for services */
struct services pacserve;
struct services pacdbserve;
@@ -97,13 +99,27 @@ int write_log(FILE *stream, const char *format, ...);
/* get_fqdn */
char * get_fqdn(const char * hostname, const char * domainname);
/* get_url */
-char * get_url(const char * hostname, const uint16_t port, const char * uri);
+char * get_url(const char * hostname, const char * address, const uint16_t port, const char * uri);
/* add_host */
-int add_host(const char * host, const uint16_t port, const char * type);
+int add_host(const char * host, const char * address, const uint16_t port, const char * type);
/* remove_host */
int remove_host(const char * host, const char * type);
+/* resolve_callback */
+static void resolve_callback(AvahiServiceResolver *r,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiResolverEvent event,
+ const char *name,
+ const char *type,
+ const char *domain,
+ const char *host,
+ const AvahiAddress *address,
+ uint16_t port,
+ AvahiStringList *txt,
+ AvahiLookupResultFlags flags,
+ void* userdata);
/* browse_callback */
static void browse_callback(AvahiServiceBrowser *b,
AvahiIfIndex interface,
@@ -112,12 +128,12 @@ static void browse_callback(AvahiServiceBrowser *b,
const char *name,
const char *type,
const char *domain,
- AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
+ AvahiLookupResultFlags flags,
void* userdata);
/* client_callback */
static void client_callback(AvahiClient *c,
AvahiClientState state,
- AVAHI_GCC_UNUSED void * userdata);
+ void * userdata);
/* get_http_code */
static void * get_http_code(void * data);