util  Check-in [81321a2c01]

Overview
Comment:iterate, add linked list template
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 81321a2c011f659259afbc6afb6bac6d4fd8d138a1cb2164f7137b85b465d2c8
User & Date: lexi on 2022-11-01 14:33:33
Other Links: manifest | tags
Context
2022-11-01
17:28
it works!! my monster liiiiives check-in: a52546afcc user: lexi tags: trunk
14:33
iterate, add linked list template check-in: 81321a2c01 user: lexi tags: trunk
2022-10-31
23:37
fix lack of alignment and small max file size for mkup; check in missing files check-in: 7bafdb9f90 user: lexi tags: trunk
Changes

Modified wgsync/makefile from [b1a751a53e] to [11c34eecc9].

            1  +B = build
            2  +E = ext
            3  +
     1      4   pq-inc != pkg-config --cflags libpq
     2      5   pq-lib != pkg-config --libs libpq
     3      6   
     4         -cc-flags = -std=c2x $(pq-inc)
     5         -ld-flags = $(pq-lib)
            7  +wg-inc = -I$E/wglib
     6      8   
     7         -B = build
            9  +dbg-flags = $(if $(debug),-g -D_cfg_debug,)
           10  +cc-flags = -std=c2x $(pq-inc) $(wg-inc) $(dbg-flags)
           11  +ld-flags = $(pq-lib) $(dbg-flags)
           12  +
     8     13   
     9     14   # link rule 
    10     15   .PHONY: wgsync
    11         -$B/wgsync: $B/wgsync.o $B/wireguard.o | $B/
           16  +$B/wgsync: $B/wgsync.o $B/pqp.o $B/def.o $B/wireguard.o | $B/
    12     17   	$(CC) $(ld-flags) $^ -o $@
    13     18   
    14     19   # build rules 
    15     20   $B/%.o: src/%.c | $B/
    16     21   	$(CC) $(cc-flags) -c $< -o $@
    17     22   
    18         -$B/wireguard.o: ext/wglib/wireguard.c ext/wglib/wireguard.h | $B/
           23  +$B/wireguard.o: $E/wglib/wireguard.c $E/wglib/wireguard.h | $B/
    19     24   	$(CC) -std=c11 -c $< -o $@
    20     25   
    21     26   # dep listings
    22         -$B/wgsync.o: ext/wglib/wireguard.h
           27  +$B/wgsync.o: $E/wglib/wireguard.h src/pqp.h src/def.h
           28  +$B/pqp.o: src/pqp.h src/def.h 
           29  +$B/def.o: src/def.h
    23     30   
    24     31   # fetch rules
    25     32   %/:
    26     33   	mkdir -p $@
    27     34   
    28     35   wg-lib-uri = https://git.zx2c4.com/wireguard-tools/plain/contrib/embeddable-wg-library
    29         -ext/wglib/%: | ext/wglib/
           36  +$E/wglib/%: | $E/wglib/
    30     37   	curl $(wg-lib-uri)/$* >$@

Added wgsync/src/def.c version [1b046527ed].

            1  +#include "def.h"
            2  +#include <stdio.h>
            3  +#include <unistd.h>
            4  +
            5  +uint8_t g_loglevel =
            6  +#ifdef _cfg_debug
            7  +	4
            8  +#else
            9  +	3
           10  +#endif
           11  +;
           12  +
           13  +char thread_local g_logbuf [sizeof g_logbuf];
           14  +
           15  +void msg
           16  +(	uint8_t level,
           17  +	char*   tag,
           18  +	uint8_t color,
           19  +	char*   msg
           20  +) {
           21  +	if(level > g_loglevel) return;
           22  +	if(isatty(fileno(stderr))) {
           23  +		fprintf(stderr, "\x1b[1;3%cm(%s)\x1b[m %s\n",
           24  +				0x30 + color, tag, msg);
           25  +	} else {
           26  +		fprintf(stderr, "(%s) %s\n", tag, msg);
           27  +	}
           28  +}

Added wgsync/src/def.h version [4bacc7856b].

            1  +#pragma once
            2  +
            3  +/* "feature tests" */
            4  +#define _POSIX_C_SOURCE 200112L
            5  +	/*             <unistd.h> seteuid
            6  +	 * <sys/socket.h netdb.h> getnameinfo */
            7  +#define _GNU_SOURCE
            8  +	/* <net/if.h> IFNAMSIZ  [linux]
            9  +	 * <unistd.h> getresuid [linux]*/
           10  +
           11  +/* arch headers */
           12  +#include <stdint.h>
           13  +#include <stddef.h>
           14  +
           15  +#define _layout struct __attribute__((__packed__))
           16  +#define _zero(x) memset(&x, sizeof(x), 0)
           17  +#define _sz(x) (sizeof(x)/sizeof(x)[0])
           18  +#define __cat(a,b) a##b
           19  +#define _cat(a,b) __cat(a,b)
           20  +#define _strify(...) #__VA_ARGS__
           21  +
           22  +#if __STDC_VERSION__ == 202000L
           23  +/* incomplete support */
           24  +#elif __STDC_VERSION__ > 202000L
           25  +#	define null nullptr
           26  +#endif
           27  +#if __STDC_VERSION__ <= 202000L
           28  +#	define null ((void*)0)
           29  +#	define thread_local _Thread_local
           30  +#	include <stdbool.h>
           31  +#endif
           32  +
           33  +extern uint8_t g_loglevel;
           34  +extern thread_local char g_logbuf [2 * 1024];
           35  +#define _lprint(...) snprintf(g_logbuf, sizeof g_logbuf, __VA_ARGS__)
           36  +
           37  +void msg(uint8_t lvl, char* tag, uint8_t color, char* msg);
           38  +
           39  +#define _msgf(lvl, tag, color, ...) { \
           40  +	if (g_loglevel >= lvl) { \
           41  +		_lprint(__VA_ARGS__); \
           42  +		msg(lvl, tag, color, g_logbuf); \
           43  +	} \
           44  +}
           45  +
           46  +#define _fatal(str) { msg(1, "fatal", 1, (str)); exit(1); }
           47  +#define _warn(str)    msg(2, "warn", 3, (str))
           48  +#define _info(str)    msg(3, "info", 4, (str))
           49  +#define _dbg(str)     msg(4, "debug", 2, (str))
           50  +
           51  +#define _fatalf(...) _msgf(1, "fatal", 1, __VA_ARGS__)
           52  +#define _warnf(...)  _msgf(2, "warn",  3, __VA_ARGS__)
           53  +#define _infof(...)  _msgf(3, "info",  4, __VA_ARGS__)
           54  +#define _dbgf(...)   _msgf(4, "debug", 2, __VA_ARGS__)
           55  +
           56  +typedef struct string {
           57  +	size_t sz; char* ptr;
           58  +} string;

Added wgsync/src/list.h version [5c0572111c].

            1  +#ifndef _ll_delete
            2  +#define _ll_delete free
            3  +#endif
            4  +
            5  +#ifndef _ll_ffirst
            6  +#define _ll_ffirst _cat(first_,_ll_rec)
            7  +#endif
            8  +
            9  +#ifndef _ll_flast
           10  +#define _ll_flast _cat(last_,_ll_rec)
           11  +#endif
           12  +
           13  +#ifndef _ll_fnext
           14  +#define _ll_fnext _cat(next_,_ll_rec)
           15  +#endif
           16  +
           17  +#ifndef _ll_dropfn
           18  +#define _ll_dropfn _cat(_cat(_ll_ns,_),_cat(drop_, _ll_rec))
           19  +#endif
           20  +
           21  +#ifndef _ll_pushfn
           22  +#define _ll_pushfn _cat(_cat(_ll_ns,_),_cat(push_, _ll_rec))
           23  +#endif
           24  +
           25  +void _ll_dropfn
           26  +(_ll_box* box, _ll_obj* obj) {
           27  +	if(box -> _ll_ffirst == obj) {
           28  +		if(box -> _ll_flast == obj) {
           29  +			box -> _ll_ffirst = box -> _ll_flast = null;
           30  +		} else {
           31  +			box -> _ll_ffirst = obj -> _ll_fnext;
           32  +		}
           33  +	} else {
           34  +		_ll_obj* a;
           35  +		if(box -> _ll_flast == obj) {
           36  +			_ll_iter (box, a) {
           37  +				if(a->_ll_fnext == obj) {
           38  +					box -> _ll_flast = a;
           39  +					a -> _ll_fnext = null;
           40  +					goto found1;
           41  +				}
           42  +			}
           43  +			_fatal("BUG in last elt deletion routine");
           44  +			found1 :;
           45  +		} else /* in the middle */ {
           46  +			_ll_iter (box, a) {
           47  +				if(a->_ll_fnext == obj) {
           48  +					a->_ll_fnext = obj -> _ll_fnext;
           49  +					goto found2;
           50  +				}
           51  +			}
           52  +			_fatal("BUG in elt deletion routine");
           53  +			found2 :;
           54  +		}
           55  +	}
           56  +	_ll_delete (obj);
           57  +}
           58  +
           59  +#undef _ll_ffirst
           60  +#undef _ll_flast
           61  +#undef _ll_ns
           62  +#undef _ll_box
           63  +#undef _ll_obj
           64  +#undef _ll_rec
           65  +#undef _ll_iter
           66  +#undef _ll_delete

Added wgsync/src/pqp.c version [64ffbf7186].

            1  +#include "pqp.h"
            2  +#include <stdlib.h>
            3  +#include <string.h>
            4  +
            5  +typedef _layout pq_array {
            6  +	int32_t nonempty, nullable, ty, nelts, resv;
            7  +	char body [];
            8  +} pq_array;
            9  +
           10  +typedef _layout pq_array_elt {
           11  +	uint32_t sz; /* -1 for null */
           12  +	char body [];
           13  +} pq_array_elt;
           14  +
           15  +#include <stdio.h>
           16  +struct pqp_array*
           17  +pqp_array_read(const void* pqary) {
           18  +	const pq_array* pqa = pqary;
           19  +	pqp_array* r = calloc(1, sizeof(pqp_array)
           20  +		+ (sizeof(pqp_array_elt) * pqa -> nelts));
           21  +	*r = (pqp_array) {
           22  +		.ty       = ntohl(pqa -> ty),
           23  +		.nullable = ntohl(pqa -> nullable),
           24  +		.sz       = ntohl(pqa -> nelts),
           25  +	};
           26  +	const char* p = pqa -> body;
           27  +	for(size_t i = 0; i < r -> sz; ++ i) {
           28  +		const pq_array_elt* e = (void*)p;
           29  +		r -> elts[i] = (pqp_array_elt) {
           30  +			.sz = ntohl(e -> sz),
           31  +			.data = (e -> sz == pq_null ? null : e -> body),
           32  +		};
           33  +		if (e -> sz == pq_null) p += 4; /* null */
           34  +		                   else p += 4 + r->elts[i].sz;
           35  +	}
           36  +	return r;
           37  +}
           38  +
           39  +bool pqp_inet_read(const void* pqinet, struct sockaddr* d) {
           40  +	if(memcmp(pqinet,"\x02\x20\x00\x04",4) == 0) {
           41  +		uint32_t ip = 0;
           42  +		for(uint8_t i = 0; i<4; ++i) {
           43  +			ip |= (uint32_t)(((uint8_t*)pqinet)[4 + i]) << 8*i;
           44  +		}
           45  +		struct sockaddr_in* dd = (void*)d;
           46  +		_zero(*dd);
           47  +		dd -> sin_family = AF_INET;
           48  +		dd -> sin_port = 0;
           49  +		dd -> sin_addr = (struct in_addr){ip};
           50  +	} else if(memcmp(pqinet,"\x03\x80\x00\x10",4) == 0) {
           51  +		struct sockaddr_in6* dd = (void*)d;
           52  +		_zero(*dd);
           53  +		dd -> sin6_family = AF_INET6;
           54  +		dd -> sin6_port = 0;
           55  +		memcpy(&(dd->sin6_addr), pqinet+4, 16);
           56  +	} else return false;
           57  +	return true;
           58  +}

Added wgsync/src/pqp.h version [6f4d74622e].

            1  +#include "def.h"
            2  +#define pq_null  ((uint32_t)0xFFFFffff)
            3  +#include <sys/socket.h>
            4  +#include <netinet/in.h>
            5  +
            6  +typedef enum pq_array_type {
            7  +	pq_array_bool = 0x10,
            8  +	pq_array_int  = 0x17,
            9  +	pq_array_text = 0x19,
           10  +	pq_array_inet = 0x365,
           11  +} pq_array_type;
           12  +
           13  +typedef struct pqp_array_elt {
           14  +	uint32_t sz;
           15  +	const char* data;
           16  +} pqp_array_elt;
           17  +
           18  +typedef struct pqp_array {
           19  +	size_t sz;
           20  +	bool nullable;
           21  +	pq_array_type ty;
           22  +	pqp_array_elt elts [];
           23  +} pqp_array;
           24  +
           25  +/* for receiving values from pqp_inet_read */
           26  +typedef union pqp_sockstore {
           27  +	struct sockaddr sock;
           28  +	struct sockaddr_in sock_in;
           29  +	struct sockaddr_in6 sock_in6;
           30  +} pqp_sockstore;
           31  +
           32  +struct pqp_array* pqp_array_read(const void* pqary);
           33  +bool pqp_inet_read(const void* pqinet, struct sockaddr* d);

Modified wgsync/src/wgsync.c from [dbf75c60c6] to [40df359611].

            1  +#include "def.h"
            2  +#include "pqp.h"
            3  +
            4  +/* libc */
            5  +#include <stdlib.h>
            6  +#include <stdio.h>
            7  +#include <string.h>
            8  +
            9  +/* posix */
           10  +#include <netinet/in.h>
           11  +#include <unistd.h>
           12  +#include <sys/socket.h>
           13  +#include <netdb.h>
           14  +
           15  +/* libs */
           16  +#include <wireguard.h>
           17  +
     1     18   #include <libpq-fe.h>
     2     19   
           20  +
           21  +size_t dumpEndpoint(char* d, const wg_endpoint* const e) {
           22  +	const struct sockaddr* addr;
           23  +	size_t len;
           24  +	switch(e->addr.sa_family) {
           25  +		case AF_INET: addr = (void*)&(e->addr4); len = sizeof e->addr4; break;
           26  +		case AF_INET6: addr = (void*)&(e->addr6); len = sizeof e->addr6; break;
           27  +		case 0: strcpy(d, "<endpoint unset>"); return 16;
           28  +		default: strcpy(d, "<bad endpoint>"); return 14;
           29  +	}
           30  +	char bip[256], bsrv[16];
           31  +	getnameinfo(addr, len,
           32  +			bip,  sizeof bip,
           33  +			bsrv, sizeof bsrv,
           34  +			NI_NUMERICHOST | NI_NUMERICSERV);
           35  +	return sprintf(d, "%s:%s", bip, bsrv);
           36  +}
           37  +
           38  +size_t dumpAllowedIP(char* d, const wg_allowedip* aip) {
           39  +		union {
           40  +			struct sockaddr_in  ip4;
           41  +			struct sockaddr_in6 ip6;
           42  +		} kinds;
           43  +		size_t len;
           44  +		switch(aip->family) {
           45  +			case AF_INET: {
           46  +				kinds.ip4 = (struct sockaddr_in) {
           47  +					.sin_family = AF_INET,
           48  +					.sin_port = 0,
           49  +					.sin_addr = aip->ip4,
           50  +				};
           51  +				len = sizeof kinds.ip4;
           52  +			break;}
           53  +			case AF_INET6: {
           54  +				kinds.ip6 = (struct sockaddr_in6) {
           55  +					.sin6_family = AF_INET6,
           56  +					.sin6_port = 0,
           57  +					.sin6_flowinfo = 0,
           58  +					.sin6_scope_id = 0,
           59  +					.sin6_addr = aip->ip6,
           60  +				};
           61  +				len = sizeof kinds.ip6;
           62  +			break;}
           63  +			case 0: strcpy(d, "<no IP>"); return 7;
           64  +			default: strcpy(d, "<non-IP address>"); return 16;
           65  +		}
           66  +		char bip[256], bsrv[2];
           67  +		getnameinfo((void*)&kinds, len,
           68  +				bip,  sizeof bip,
           69  +				bsrv, sizeof bsrv,
           70  +				NI_NUMERICHOST | NI_NUMERICSERV);
           71  +		return sprintf(d, "%s/%u", bip, aip->cidr);
           72  +}
           73  +
           74  +bool compare_allowedip
           75  +(	const wg_allowedip* const a,
           76  +	const wg_allowedip* const b
           77  +) {
           78  +	if(a -> family != b -> family) return false;
           79  +	if(a -> cidr != b -> cidr) return false;
           80  +	switch(a->family) {
           81  +		case AF_INET:
           82  +			if(a -> ip4.s_addr != b -> ip4.s_addr) return false;
           83  +			break;
           84  +		case AF_INET6:
           85  +			if(memcmp(a -> ip6.s6_addr, b -> ip6.s6_addr, sizeof(a->ip6.s6_addr)) != 0)
           86  +				return false;
           87  +			break;
           88  +	}
           89  +	return true;
           90  +}
           91  +
           92  +wg_allowedip
           93  +inet_to_allowedip(const char* data) {
           94  +	pqp_sockstore ss;
           95  +	if(!pqp_inet_read(data, &ss.sock))
           96  +		_fatal("bad IP value in database");
           97  +
           98  +	wg_allowedip wgip = {
           99  +		.family = ss.sock.sa_family,
          100  +		.next_allowedip = null,
          101  +	};
          102  +	switch(ss.sock.sa_family) {
          103  +		case AF_INET:
          104  +			wgip.cidr = 32;
          105  +			wgip.ip4 = ss.sock_in.sin_addr;
          106  +			break;
          107  +		case AF_INET6:
          108  +			wgip.cidr = 128;
          109  +			wgip.ip6 = ss.sock_in6.sin6_addr;
          110  +			break;
          111  +		default: _fatal("unhandled address family");
          112  +	}
          113  +	return wgip;
          114  +}
          115  +
          116  +void wgd_free_peer(wg_peer* peer) {
          117  +	wg_allowedip *allowedip, *na;
          118  +	/* from ext/wglib/wireguard.c:1486 */
          119  +	for (
          120  +		allowedip = peer->first_allowedip,
          121  +			na = allowedip ? allowedip->next_allowedip : NULL; 
          122  +		allowedip;
          123  +		allowedip = na,
          124  +			na = allowedip ? allowedip->next_allowedip : NULL
          125  +	) free(allowedip);
          126  +	/* end import */
          127  +	free(peer);
          128  +}
          129  +
          130  +/* linked list manipulation routines */
          131  +
          132  +#define _ll_rec peer
          133  +#define _ll_box wg_device
          134  +#define _ll_obj wg_peer
          135  +#define _ll_iter wg_for_each_peer
          136  +#define _ll_ns wgd
          137  +#include "list.h"
          138  +
          139  +#define _ll_rec allowedip
          140  +#define _ll_box wg_peer
          141  +#define _ll_obj wg_allowedip
          142  +#define _ll_iter wg_for_each_allowedip
          143  +#define _ll_ns wgd_peer
          144  +#include "list.h"
          145  +
          146  +#if 0
          147  +void wgd_drop_peer(wg_device* dev, wg_peer* peer) {
          148  +	if(dev -> first_peer == peer) {
          149  +		if(dev -> last_peer == peer) {
          150  +			dev -> first_peer = dev -> last_peer = null;
          151  +		} else {
          152  +			dev -> first_peer = peer -> next_peer;
          153  +		}
          154  +	} else {
          155  +		wg_peer* p;
          156  +		if(dev -> last_peer == peer) {
          157  +			wg_for_each_peer(dev, p) {
          158  +				if(p->next_peer == peer) {
          159  +					dev -> last_peer = p;
          160  +					p->next_peer = null;
          161  +					goto found1;
          162  +				}
          163  +			}
          164  +			_fatal("BUG in last peer deletion routine");
          165  +			found1 :;
          166  +		} else /* in the middle */ {
          167  +			wg_for_each_peer(dev, p) {
          168  +				if(p->next_peer == peer) {
          169  +					p->next_peer = peer -> next_peer;
          170  +					goto found2;
          171  +				}
          172  +			}
          173  +			_fatal("BUG in peer deletion routine");
          174  +			found2 :;
          175  +		}
          176  +	}
          177  +	wgd_free_peer(peer);
          178  +}
          179  +void wgd_peer_drop_ip(wg_peer* peer, wg_allowedip* ip) {
          180  +	if(peer -> first_allowedip == ip) {
          181  +		if(peer -> last_allowedip == ip) {
          182  +			peer -> first_allowedip = peer -> last_allowedip = null;
          183  +		} else {
          184  +			peer -> first_allowedip = peer -> next_allowedip;
          185  +		}
          186  +	} else {
          187  +		wg_allowedip* a;
          188  +		if(peer -> last_allowedip == ip) {
          189  +			wg_for_each_allowedip(peer, a) {
          190  +				if(a->next_allowedip == ip) {
          191  +					peer -> last_allowedip = a;
          192  +					a->next_allowedip = null;
          193  +					goto found1;
          194  +				}
          195  +			}
          196  +			_fatal("BUG in last aIP deletion routine");
          197  +			found1 :;
          198  +		} else /* in the middle */ {
          199  +			wg_for_each_allowedip(peer, a) {
          200  +				if(a->next_allowedip == ip) {
          201  +					a->next_allowedip = ip -> next_allowedip;
          202  +					goto found2;
          203  +				}
          204  +			}
          205  +			_fatal("BUG in aIP deletion routine");
          206  +			found2 :;
          207  +		}
          208  +	}
          209  +	free(ip);
          210  +}
          211  +#endif
          212  +
          213  +void syncauth(PGconn* db, const char* wgdev) {
          214  +	wg_device* wg;
          215  +	if (wg_get_device(&wg, wgdev))
          216  +		_fatal("no wireguard device by that name");
          217  +
          218  +	bool dirty = false;
          219  +	size_t peerc = 0;
          220  +	{ wg_peer* p; wg_for_each_peer(wg, p) ++ peerc; };
          221  +
          222  +	bool valid_peers [peerc];
          223  +	_zero(valid_peers);
          224  +
          225  +	PGresult* rows = PQexecPrepared(db, "get_hosts",
          226  +			0, null, null, null, 1);
          227  +	if(!(rows && PQresultStatus(rows) == PGRES_TUPLES_OK))
          228  +		_fatal(PQerrorMessage(db));
          229  +
          230  +	size_t rowc = PQntuples(rows);
          231  +	for(size_t i = 0; i < rowc; ++i) {
          232  +		const char* key_b64 = PQgetvalue(rows, i, 0);
          233  +
          234  +		const char* aryraw = PQgetvalue(rows, i, 1);
          235  +		pqp_array* ips = pqp_array_read(aryraw);
          236  +		_dbgf("DB has peer %s", key_b64);
          237  +		if(ips->ty != pq_array_inet)
          238  +			_fatal("incorrect array type returned from DB");
          239  +
          240  +		wg_key key;
          241  +		if (wg_key_from_base64(key, key_b64) < 0) {
          242  +			_warnf("invalid key in database: %s", key_b64);
          243  +			continue;
          244  +		}
          245  +
          246  +		wg_peer* found = null;
          247  +		{ size_t j=0; wg_peer* p; wg_for_each_peer(wg, p) {
          248  +			if(memcmp(p->public_key, key, sizeof key) == 0) {
          249  +				_dbgf("validating peer %s", key_b64);
          250  +				valid_peers[j] = true;
          251  +				found = p;
          252  +				break;
          253  +			}
          254  +		++j;}}
          255  +
          256  +		if (found) {
          257  +			/* compare and update IPs if necessary */
          258  +			bool goodIPs [ips -> sz]; _zero(goodIPs);
          259  +			/* extant IPs that are not marked good by the
          260  +			 * end of the following loop must be deleted
          261  +			 * from memory */
          262  +			size_t goodIPc = 0;
          263  +			for (size_t j = 0; j < ips -> sz; ++j) {
          264  +				char inetstr[256];
          265  +				wg_allowedip aip = inet_to_allowedip(ips -> elts[j].data);
          266  +				dumpAllowedIP(inetstr, &aip);
          267  +				_dbgf("IP PG%zu :: %s", j, inetstr);
          268  +
          269  +				size_t l = 0;
          270  +				wg_allowedip* wgip;
          271  +				bool foundIP = false;
          272  +				wg_for_each_allowedip(found, wgip) {
          273  +					if (compare_allowedip(&aip, wgip)) {
          274  +						++goodIPc; goodIPs[l] = true;
          275  +						foundIP = true;
          276  +					}
          277  +				++l;}
          278  +				
          279  +				if(!foundIP) {
          280  +					/* this IP hasn't been loaded into the
          281  +					 * kernel yet; upload it now */
          282  +					_infof("inserting IP PG%zu %s", j, inetstr);
          283  +					dirty = true;
          284  +				}
          285  +			}
          286  +
          287  +			if(goodIPc < ips -> sz) {
          288  +				size_t l = 0;
          289  +				wg_allowedip* wgip;
          290  +				wg_for_each_allowedip(found, wgip) {
          291  +					char inetstr[256];
          292  +					dumpAllowedIP(inetstr, wgip);
          293  +					_dbgf("IP WG%zu :: %s", l, inetstr);
          294  +					if(!goodIPs[l]) {
          295  +						/* this IP is stale, delete it */
          296  +						_infof("deleting IP WG%zu %s", l, inetstr);
          297  +						dirty = true;
          298  +					}
          299  +				++l;}
          300  +			}
          301  +		} else {
          302  +			_infof("inserting key %s", key_b64);
          303  +			dirty = true;
          304  +			/* install new peer */
          305  +			for (size_t j = 0; j < ips -> sz; ++j) {
          306  +				char inetstr[256];
          307  +				wg_allowedip aip = inet_to_allowedip(ips -> elts[j].data);
          308  +				dumpAllowedIP(inetstr, &aip);
          309  +				_dbgf("new IP %zu :: %s", j, inetstr);
          310  +			}
          311  +		}
          312  +
          313  +		free(ips);
          314  +	}
          315  +	{ size_t i=0; wg_peer* p; wg_for_each_peer(wg, p) {
          316  +		if(valid_peers[i] == false) {
          317  +			char b64 [128];
          318  +			wg_key_to_base64(b64, p->public_key);
          319  +			_infof("dropping peer %s", b64);
          320  +			wgd_drop_peer(wg, p);
          321  +			dirty = true;
          322  +		}
          323  +	++i;}}
          324  +
          325  +	_dbg("final peer list:");
          326  +	{ size_t j=0; wg_peer* p; wg_for_each_peer(wg, p) {
          327  +		char b64 [128];
          328  +		wg_key_to_base64(b64, p->public_key);
          329  +		_dbgf("P%zu :: %s", j, b64);
          330  +	++j;}}
          331  +	
          332  +	if(dirty) wg_set_device(wg);
          333  +
          334  +	PQclear(rows);
          335  +}
          336  +
     3    337   int main(int argc, char** argv) {
          338  +	setvbuf(stderr, null, _IONBF, 0);
          339  +	if (argc < 3) {
          340  +		_fatal("missing device name");
          341  +	}
          342  +
          343  +	const char* arg_mode = argv[1];
          344  +	const char* arg_devname = argv[2];
          345  +
          346  +	/* mostly for the sake of debugging, allow the
          347  +	 * binary to be run from sudo without losing
          348  +	 * postgres peer credentials */
          349  +	if(geteuid() == 0) {
          350  +		char* suid = getenv("SUDO_UID");
          351  +		char* susr = getenv("SUDO_USER");
          352  +		if(suid) seteuid(atoi(suid));
          353  +		if(susr) setenv("USER",getenv("SUDO_USER"), 1);
          354  +	}
          355  +
          356  +	PGconn* db = PQconnectdb("dbname=domain");
          357  +	if(PQstatus(db) != CONNECTION_OK) 
          358  +		_fatal(PQerrorMessage(db));
          359  +
          360  +	PGresult* q_get_hosts = PQprepare(db, "get_hosts",
          361  +		"select h.ref, array_remove(array_agg(wgv4::inet)"
          362  +		                        "|| array_agg(wgv6::inet), null)"
          363  +			"from ns, hostref h "
          364  +			"where ns.host = h.host and kind = 'pubkey' "
          365  +			" group by h.host, h.ref;", 0, null);
          366  +		/*"select ns.wgv4::inet, ns.wgv6::inet, h.ref from ns "
          367  +			"right join hostref h "
          368  +				"on h.host = ns.host "
          369  +			"where h.kind = 'pubkey';"*/
          370  +	if(!(q_get_hosts && PQresultStatus(q_get_hosts) == PGRES_COMMAND_OK))
          371  +		_fatal(PQerrorMessage(db));
          372  +	PQclear(q_get_hosts);
          373  +
          374  +	/* we're going to interact with WG now;
          375  +	 * get our superpowers back if we lost them */
          376  +	{uid_t svuid;
          377  +	getresuid(null, null, &svuid);
          378  +	if (svuid == 0) setuid(0);}
          379  +
          380  +	if(strcmp(arg_mode, "sync") == 0) {
          381  +		syncauth(db, arg_devname);
          382  +	} else if(strcmp(arg_mode, "wait") == 0) {
          383  +		/* foreground daemon */
          384  +	} else if(strcmp(arg_mode, "fork") == 0) {
          385  +		/* background daemon */
          386  +	} else {
          387  +		_fatal("valid modes are sync, wait, and fork");
          388  +	}
          389  +	/* other possibilities: a mode that generates an eventfd
          390  +	 * and provides it on fd4 to a subordinate process, or
          391  +	 * sends it with SCM_RIGHTS */
          392  +
          393  +	PQfinish(db);
     4    394   	return 0;
     5    395   }