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: |
81321a2c011f659259afbc6afb6bac6d |
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 }