-void maskcpy(char *a, char *b, int masklen, int len)
-{
- int i, m;
-cp
- for(m = masklen, i = 0; m >= 8; m -= 8, i++)
- a[i] = b[i];
-
- if(m)
- {
- a[i] = b[i] & (0x100 - (1 << m));
- i++;
- }
-
- for(; i < len; i++)
- a[i] = 0;
+void sockaddrcpy(sockaddr_t *a, const sockaddr_t *b) {
+ if(b->sa.sa_family != AF_UNKNOWN) {
+ *a = *b;
+ } else {
+ a->unknown.family = AF_UNKNOWN;
+ a->unknown.address = xstrdup(b->unknown.address);
+ a->unknown.port = xstrdup(b->unknown.port);
+ }
+}
+
+void sockaddrfree(sockaddr_t *a) {
+ if(a->sa.sa_family == AF_UNKNOWN) {
+ free(a->unknown.address);
+ free(a->unknown.port);
+ }
+}
+
+void sockaddrunmap(sockaddr_t *sa) {
+ if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
+ sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3];
+ sa->in.sin_family = AF_INET;
+ }
+}
+
+void sockaddr_setport(sockaddr_t *sa, const char *port) {
+ uint16_t portnum = htons(atoi(port));
+
+ if(!portnum) {
+ return;
+ }
+
+ switch(sa->sa.sa_family) {
+ case AF_INET:
+ sa->in.sin_port = portnum;
+ break;
+
+ case AF_INET6:
+ sa->in6.sin6_port = portnum;
+ break;
+
+ case AF_UNKNOWN:
+ free(sa->unknown.port);
+ sa->unknown.port = xstrdup(port);
+
+ default:
+ return;
+ }
+}
+
+bool is_local_connection(const sockaddr_t *sa) {
+ switch(sa->sa.sa_family) {
+ case AF_INET:
+ // 127.0.0.0/8
+ return ntohl(sa->in.sin_addr.s_addr) >> 24 == 127;
+
+ case AF_INET6:
+ return IN6_IS_ADDR_LOOPBACK(&sa->in6.sin6_addr);
+
+ case AF_UNIX:
+ return true;
+
+ default:
+ return false;
+ }