static inline rsRetVal addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) { int r; struct sockaddr_storage *keybuf; dnscache_entry_t *etry = NULL; DEFiRet; CHKmalloc(etry = MALLOC(sizeof(dnscache_entry_t))); CHKiRet(resolveAddr(addr, etry)); memcpy(&etry->addr, addr, SALEN((struct sockaddr*) addr)); etry->nUsed = 0; *pEtry = etry; CHKmalloc(keybuf = malloc(sizeof(struct sockaddr_storage))); memcpy(keybuf, addr, sizeof(struct sockaddr_storage)); pthread_rwlock_unlock(&dnsCache.rwlock); /* release read lock */ pthread_rwlock_wrlock(&dnsCache.rwlock); /* and re-aquire for writing */ r = hashtable_insert(dnsCache.ht, keybuf, *pEtry); if(r == 0) { DBGPRINTF("dnscache: inserting element failed\n"); } pthread_rwlock_unlock(&dnsCache.rwlock); pthread_rwlock_rdlock(&dnsCache.rwlock); /* we need this again */ finalize_it: if(iRet != RS_RET_OK && etry != NULL) { /* Note: sub-fields cannot be populated in this case */ free(etry); } RETiRet; }
static int notify_send(struct sockaddr *to, char *zone_name) { int s; dns_sock_t *sock; if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { plog_error(LOG_ERR, MODULE, "socket() failed"); return -1; } if (connect(s, to, SALEN(to)) < 0) { plog_error(LOG_ERR, MODULE, "connect() failed"); close(s); return -1; } if ((sock = dns_sock_udp_new(s, &SockPropNotify)) == NULL) { plog_error(LOG_ERR, MODULE, "dns_sock_add_udp() failed"); close(s); return -1; } if (notify_send_message(sock, zone_name) < 0) { plog(LOG_ERR, "%s: dns_notify_send() failed", MODULE); dns_sock_free(sock); return -1; } return 0; }
int dns_util_socket_sa(int pf, int type, struct sockaddr *sa) { int s, on = 1; if ((s = socket(pf, type, 0)) < 0) { plog_error(LOG_ERR, MODULE, "socket() failed"); return -1; } if (pf == PF_INET6) { if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { plog_error(LOG_ERR, MODULE, "setsockopt(IPV6_V6ONLY) failed"); return -1; } } if (type == SOCK_STREAM) { if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { plog_error(LOG_ERR, MODULE, "setsockopt(SO_REUSEADDR) failed"); return -1; } } if (bind(s, (SA *) sa, SALEN(sa)) < 0) { plog_error(LOG_ERR, MODULE, "bind() failed"); return -1; } return s; }
addEntry(struct sockaddr_storage *const addr, dnscache_entry_t **const pEtry) { int r; dnscache_entry_t *etry = NULL; DEFiRet; /* entry still does not exist, so add it */ struct sockaddr_storage *const keybuf = malloc(sizeof(struct sockaddr_storage)); CHKmalloc(keybuf); CHKmalloc(etry = malloc(sizeof(dnscache_entry_t))); resolveAddr(addr, etry); assert(etry != NULL); memcpy(&etry->addr, addr, SALEN((struct sockaddr*) addr)); etry->nUsed = 0; if(dnscacheEnableTTL) { etry->validUntil = time(NULL) + dnscacheDefaultTTL; } memcpy(keybuf, addr, sizeof(struct sockaddr_storage)); r = hashtable_insert(dnsCache.ht, keybuf, etry); if(r == 0) { DBGPRINTF("dnscache: inserting element failed\n"); } *pEtry = etry; finalize_it: if(iRet != RS_RET_OK) { free(keybuf); } RETiRet; }
int dns_util_sa2str_wop(char *buf, int bufmax, struct sockaddr *sa) { if (getnameinfo(sa, SALEN(sa), buf, bufmax, NULL, 0, NI_NUMERICHOST) != 0) { plog_error(LOG_ERR, MODULE, "getnameinfo() failed"); return -1; } return 0; }
/* Our hash function. * TODO: check how well it performs on socket addresses! */ static unsigned int hash_from_key_fn(void *k) { int len; uchar *rkey = (uchar*) k; /* we treat this as opaque bytes */ unsigned hashval = 1; len = SALEN((struct sockaddr*)k); while(len--) hashval = hashval * 33 + *rkey++; return hashval; }
/* * \fn hip_dht_select_server() * * \param addr pointer to store address of the server * \return Returns 0 on success, -1 on error. * * \brief Select the address of the DHT server to use. */ int hip_dht_select_server(struct sockaddr *addr) { /* * we leave room for more complex server selection schemes here * * for now, a single server+port is specified via the conf file * */ if (VALID_FAM(&HCNF.dht_server)) { memcpy(addr, &HCNF.dht_server, SALEN(&HCNF.dht_server)); return(0); } return(-1); }
/* Print an allowed sender list. The caller must tell us which one. * iListToPrint = 1 means UDP, 2 means TCP * rgerhards, 2005-09-27 */ static void PrintAllowedSenders(int iListToPrint) { struct AllowedSenders *pSender; uchar szIP[64]; assert((iListToPrint == 1) || (iListToPrint == 2) #ifdef USE_GSSAPI || (iListToPrint == 3) #endif ); dbgprintf("Allowed %s Senders:\n", (iListToPrint == 1) ? "UDP" : #ifdef USE_GSSAPI (iListToPrint == 3) ? "GSS" : #endif "TCP"); pSender = (iListToPrint == 1) ? pAllowedSenders_UDP : #ifdef USE_GSSAPI (iListToPrint == 3) ? pAllowedSenders_GSS : #endif pAllowedSenders_TCP; if(pSender == NULL) { dbgprintf("\tNo restrictions set.\n"); } else { while(pSender != NULL) { if (F_ISSET(pSender->allowedSender.flags, ADDR_NAME)) dbgprintf ("\t%s\n", pSender->allowedSender.addr.HostWildcard); else { if(mygetnameinfo (pSender->allowedSender.addr.NetAddr, SALEN(pSender->allowedSender.addr.NetAddr), (char*)szIP, 64, NULL, 0, NI_NUMERICHOST) == 0) { dbgprintf ("\t%s/%u\n", szIP, pSender->SignificantBits); } else { /* getnameinfo() failed - but as this is only a * debug function, we simply spit out an error and do * not care much about it. */ dbgprintf("\tERROR in getnameinfo() - something may be wrong " "- ignored for now\n"); } } pSender = pSender->pNext; } } }
static void proxy_init_front (proxy_t *p, char *front) { struct sockaddr_in6 ss; sockaddr_init(SA(&ss), front); p->sock_front = socket(SAFAM(&ss), SOCK_STREAM|O_NONBLOCK, 0); ASSERT(p->sock_front >= 0); int opt = 1; setsockopt(p->sock_front, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (0 > bind(p->sock_front, SA(&ss), SALEN(&ss))) { LOG("front(%d).bind(%s) failed", p->sock_front, front); exit(1); } LOG("front(%s) ready", front); }
int dns_util_str2sa(struct sockaddr *sa, char *addr, uint16_t port) { struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(addr, NULL, &hints, &res) != 0) { plog(LOG_ERR, "%s: getaddrinfo() failed", MODULE); return -1; } memcpy(sa, res->ai_addr, SALEN(res->ai_addr)); freeaddrinfo(res); dns_util_sasetport(sa, port); return 0; }
addEntry(struct sockaddr_storage *const addr, dnscache_entry_t **const pEtry) { int r; struct sockaddr_storage *keybuf = NULL; dnscache_entry_t *etry = NULL; DEFiRet; pthread_rwlock_wrlock(&dnsCache.rwlock); /* first check, if the entry was added in the mean time */ etry = findEntry(addr); if(etry != NULL) { FINALIZE; } /* entry still does not exist, so add it */ CHKmalloc(etry = malloc(sizeof(dnscache_entry_t))); CHKmalloc(keybuf = malloc(sizeof(struct sockaddr_storage))); CHKiRet(resolveAddr(addr, etry)); memcpy(&etry->addr, addr, SALEN((struct sockaddr*) addr)); etry->nUsed = 0; memcpy(keybuf, addr, sizeof(struct sockaddr_storage)); r = hashtable_insert(dnsCache.ht, keybuf, etry); keybuf = NULL; if(r == 0) { DBGPRINTF("dnscache: inserting element failed\n"); } finalize_it: pthread_rwlock_unlock(&dnsCache.rwlock); if(iRet == RS_RET_OK) { *pEtry = etry; } else { free(keybuf); free(etry); /* Note: sub-fields cannot be populated in this case */ } RETiRet; }
static void main_init_srv (char **urlv) { int rc, opt; struct sockaddr_storage ss; for (char **pu = urlv; *pu; ++pu) { struct item_s *srv = malloc (sizeof (struct item_s)); item_init (srv); if (!sockaddr_init (SA (&ss), *pu)) abort (); srv->events = EPOLLIN; srv->type = SERVER; srv->fd = socket (SAFAM (&ss), SOCK_STREAM | O_CLOEXEC | O_NONBLOCK, 0); ASSERT (srv->fd >= 0); opt = 1; setsockopt (srv->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); rc = bind (srv->fd, SA (&ss), SALEN (&ss)); ASSERT (rc == 0); rc = listen (srv->fd, front_backlog); ASSERT (rc == 0); struct epoll_event evt; retry_add: evt.data.ptr = srv; evt.events = EPOLLIN; rc = epoll_ctl (fd_epoll, EPOLL_CTL_ADD, srv->fd, &evt); if (rc < 0) { if (errno == EINTR) goto retry_add; ASSERT (rc == 0); } } }
void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) { char address[NI_MAXHOST]; char port[NI_MAXSERV]; char *scopeid; int err; if(sa->sa.sa_family == AF_UNSPEC) { if(addrstr) *addrstr = xstrdup("unspec"); if(portstr) *portstr = xstrdup("unspec"); return; } else if(sa->sa.sa_family == AF_UNKNOWN) { if(addrstr) *addrstr = xstrdup(sa->unknown.address); if(portstr) *portstr = xstrdup(sa->unknown.port); return; } err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV); if(err) { logger(DEBUG_ALWAYS, LOG_ERR, "Error while translating addresses: %s", err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); abort(); } scopeid = strchr(address, '%'); if(scopeid) *scopeid = '\0'; /* Descope. */ if(addrstr) *addrstr = xstrdup(address); if(portstr) *portstr = xstrdup(port); }
char *sockaddr2hostname(const sockaddr_t *sa) { char *str; char address[NI_MAXHOST] = "unknown"; char port[NI_MAXSERV] = "unknown"; int err; if(sa->sa.sa_family == AF_UNSPEC) { xasprintf(&str, "unspec port unspec"); return str; } else if(sa->sa.sa_family == AF_UNKNOWN) { xasprintf(&str, "%s port %s", sa->unknown.address, sa->unknown.port); return str; } err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV)); if(err) { logger(DEBUG_ALWAYS, LOG_ERR, "Error while looking up hostname: %s", err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err)); } xasprintf(&str, "%s port %s", address, port); return str; }
resolveAddr(struct sockaddr_storage *addr, dnscache_entry_t *etry) { DEFiRet; int error; sigset_t omask, nmask; struct addrinfo hints, *res; char szIP[80]; /* large enough for IPv6 */ char fqdnBuf[NI_MAXHOST]; rs_size_t fqdnLen; rs_size_t i; error = mygetnameinfo((struct sockaddr *)addr, SALEN((struct sockaddr *)addr), (char*) szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST); if(error) { dbgprintf("Malformed from address %s\n", gai_strerror(error)); ABORT_FINALIZE(RS_RET_INVALID_SOURCE); } if(!glbl.GetDisableDNS()) { sigemptyset(&nmask); sigaddset(&nmask, SIGHUP); pthread_sigmask(SIG_BLOCK, &nmask, &omask); error = mygetnameinfo((struct sockaddr *)addr, SALEN((struct sockaddr *) addr), fqdnBuf, NI_MAXHOST, NULL, 0, NI_NAMEREQD); if(error == 0) { memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_flags = AI_NUMERICHOST; /* we now do a lookup once again. This one should fail, * because we should not have obtained a non-numeric address. If * we got a numeric one, someone messed with DNS! */ if(getaddrinfo (fqdnBuf, NULL, &hints, &res) == 0) { uchar szErrMsg[1024]; freeaddrinfo (res); /* OK, we know we have evil. The question now is what to do about * it. One the one hand, the message might probably be intended * to harm us. On the other hand, losing the message may also harm us. * Thus, the behaviour is controlled by the $DropMsgsWithMaliciousDnsPTRRecords * option. If it tells us we should discard, we do so, else we proceed, * but log an error message together with it. * time being, we simply drop the name we obtained and use the IP - that one * is OK in any way. We do also log the error message. rgerhards, 2007-07-16 */ if(glbl.GetDropMalPTRMsgs() == 1) { snprintf((char*)szErrMsg, sizeof(szErrMsg), "Malicious PTR record, message dropped " "IP = \"%s\" HOST = \"%s\"", szIP, fqdnBuf); LogError(0, RS_RET_MALICIOUS_ENTITY, "%s", szErrMsg); pthread_sigmask(SIG_SETMASK, &omask, NULL); ABORT_FINALIZE(RS_RET_MALICIOUS_ENTITY); } /* Please note: we deal with a malicous entry. Thus, we have crafted * the snprintf() below so that all text is in front of the entry - maybe * it contains characters that make the message unreadable * (OK, I admit this is more or less impossible, but I am paranoid...) * rgerhards, 2007-07-16 */ snprintf((char*)szErrMsg, sizeof(szErrMsg), "Malicious PTR record (message accepted, but used IP " "instead of PTR name: IP = \"%s\" HOST = \"%s\"", szIP, fqdnBuf); LogError(0, NO_ERRCODE, "%s", szErrMsg); error = 1; /* that will trigger using IP address below. */ } else {/* we have a valid entry, so let's create the respective properties */ fqdnLen = strlen(fqdnBuf); prop.CreateStringProp(&etry->fqdn, (uchar*)fqdnBuf, fqdnLen); for(i = 0 ; i < fqdnLen ; ++i) fqdnBuf[i] = tolower(fqdnBuf[i]); prop.CreateStringProp(&etry->fqdnLowerCase, (uchar*)fqdnBuf, fqdnLen); } } pthread_sigmask(SIG_SETMASK, &omask, NULL); } finalize_it: if(iRet != RS_RET_OK) { strcpy(szIP, "?error.obtaining.ip?"); error = 1; /* trigger hostname copies below! */ } /* we need to create the inputName property (only once during our lifetime) */ prop.CreateStringProp(&etry->ip, (uchar*)szIP, strlen(szIP)); if(error || glbl.GetDisableDNS()) { dbgprintf("Host name for your address (%s) unknown\n", szIP); prop.AddRef(etry->ip); etry->fqdn = etry->ip; prop.AddRef(etry->ip); etry->fqdnLowerCase = etry->ip; } setLocalHostName(etry); RETiRet; }
static int key_equals_fn(void *key1, void *key2) { return (SALEN((struct sockaddr*)key1) == SALEN((struct sockaddr*) key2) && !memcmp(key1, key2, SALEN((struct sockaddr*) key1))); }
/* * \fn hip_dht_resolve_hi() * * \param hi pointer to host identity whose name, LSI, or HIT can be used * for lookups, and the HIT and address may be updated * \param retry if TRUE, we'll spawn a new thread an retry multiple times * without blocking * * \return returns -1 if there is a problem, 0 otherwise * * \brief Given a Host Identity, perform a DHT lookup using its HIT and store * any resulting address in the hi_node. If the HIT is missing, perform a HIT * lookup in the DHT using the name and/or LSI. */ int hip_dht_resolve_hi(hi_node *hi, int retry) { int err; struct sockaddr_storage ss_addr; struct sockaddr *addr = (struct sockaddr*) &ss_addr; sockaddr_list *list; char hit_str[INET6_ADDRSTRLEN]; #ifndef __WIN32__ pthread_attr_t attr; pthread_t thr; #endif if (hip_dht_select_server(addr) < 0) { return(0); /* prevents unneccessary thread creation */ } /* When retry is turned on, a separate thread will be forked that * will perform the DHT lookup(s), retry a certain number of times, * and exit */ if (retry == TRUE) { #ifdef __WIN32__ _beginthread(hip_dht_resolve_hi_thread, 0, (void *)hi); #else pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&thr, &attr, hip_dht_resolve_hi_thread, hi); #endif return(0); /* We have been recursively called from a thread */ } else if (retry == 2) { retry = TRUE; /* used for calls below... */ } /* * First locate the HIT using the peer's name if this HIT is missing. */ if (hits_equal(hi->hit, zero_hit)) { if (hi->name_len == 0) { log_(NORM, "HIT and name not present, unable to perform" " DHT lookup.\n"); return(-1); } log_(NORM, "HIT not present for peer %s, performing DHT lookup " "using the name '%s'.\n", logaddr(SA(&hi->lsi)), hi->name); if ((err = hip_dht_lookup_hit_by_name(hi->name, &hi->hit, retry)) < 0) { /* no HIT from name, so we cannot do address lookup */ log_(WARN, "Unable to find HIT for %s in the DHT.\n", logaddr(SA(&hi->lsi))); return(err); } else { hit_to_str(hit_str, hi->hit); log_(NORM, "Discovered HIT for peer %s using the DHT: " "%s\n", hi->name, hit_str); } } /* * Look up current IP address using HIT as key */ memset(addr, 0, sizeof(struct sockaddr_storage)); addr->sa_family = AF_INET; if ((err = hip_dht_lookup_address(&hi->hit, addr, retry)) < 0) { return(err); } /* add address to list, checking if first item is empty */ pthread_mutex_lock(&hi->addrs_mutex); if ((hi->addrs.status == DELETED) || !VALID_FAM(&hi->addrs.addr)) { memcpy(&hi->addrs.addr, addr, SALEN(addr)); hi->addrs.if_index = 0; hi->addrs.lifetime = 0; hi->addrs.status = UNVERIFIED; hi->addrs.nonce = 0; gettimeofday(&hi->addrs.creation_time, NULL); } else { list = &hi->addrs; add_address_to_list(&list, addr, 0); } pthread_mutex_unlock(&hi->addrs_mutex); return(0); }
void do_outgoing_connection(connection_t *c) { char *address, *port, *space; struct addrinfo *proxyai = NULL; int result; if(!c->outgoing) { logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name); abort(); } begin: if(!c->outgoing->ai) { if(!c->outgoing->cfg) { ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s", c->name); c->status.remove = true; retry_outgoing(c->outgoing); c->outgoing = NULL; return; } get_config_string(c->outgoing->cfg, &address); space = strchr(address, ' '); if(space) { port = xstrdup(space + 1); *space = 0; } else { if(!get_config_string(lookup_config(c->config_tree, "Port"), &port)) port = xstrdup("655"); } c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM); free(address); free(port); c->outgoing->aip = c->outgoing->ai; c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg); } if(!c->outgoing->aip) { if(c->outgoing->ai) freeaddrinfo(c->outgoing->ai); c->outgoing->ai = NULL; goto begin; } memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen); c->outgoing->aip = c->outgoing->aip->ai_next; if(c->hostname) free(c->hostname); c->hostname = sockaddr2hostname(&c->address); ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name, c->hostname); if(!proxytype) { c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); } else if(proxytype == PROXY_EXEC) { do_outgoing_pipe(c, proxyhost); } else { proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM); if(!proxyai) goto begin; ifdebug(CONNECTIONS) logger(LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport); c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP); } if(c->socket == -1) { ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno)); goto begin; } if(proxytype != PROXY_EXEC) configure_tcp(c); #ifdef FD_CLOEXEC fcntl(c->socket, F_SETFD, FD_CLOEXEC); #endif if(proxytype != PROXY_EXEC) { #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) int option = 1; if(c->address.sa.sa_family == AF_INET6) setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); #endif bind_to_interface(c->socket); } /* Connect */ if(!proxytype) { result = connect(c->socket, &c->address.sa, SALEN(c->address.sa)); } else if(proxytype == PROXY_EXEC) { result = 0; } else { result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen); freeaddrinfo(proxyai); } if(result == -1) { if(sockinprogress(sockerrno)) { c->status.connecting = true; return; } closesocket(c->socket); ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, sockstrerror(sockerrno)); goto begin; } finish_connecting(c); return; }
int setup_vpn_in_socket(const sockaddr_t *sa) { int nfd; char *addrstr; int option; nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP); if(nfd < 0) { logger(LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno)); return -1; } #ifdef FD_CLOEXEC fcntl(nfd, F_SETFD, FD_CLOEXEC); #endif #ifdef O_NONBLOCK { int flags = fcntl(nfd, F_GETFL); if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { closesocket(nfd); logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno)); return -1; } } #elif defined(WIN32) { unsigned long arg = 1; if(ioctlsocket(nfd, FIONBIO, &arg) != 0) { closesocket(nfd); logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno)); return -1; } } #endif option = 1; setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option)); if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf))) logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno)); if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf))) logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno)); #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); #endif #if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT) #define IP_DONTFRAGMENT IP_DONTFRAG #endif #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) if(myself->options & OPTION_PMTU_DISCOVERY) { option = IP_PMTUDISC_DO; setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option)); } #elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT) if(myself->options & OPTION_PMTU_DISCOVERY) { option = 1; setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option)); } #endif #if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) if(myself->options & OPTION_PMTU_DISCOVERY) { option = IPV6_PMTUDISC_DO; setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option)); } #elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG) if(myself->options & OPTION_PMTU_DISCOVERY) { option = 1; setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option)); } #endif if (!bind_to_interface(nfd)) { closesocket(nfd); return -1; } if(bind(nfd, &sa->sa, SALEN(sa->sa))) { closesocket(nfd); addrstr = sockaddr2hostname(sa); logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno)); free(addrstr); return -1; } return nfd; } /* int setup_vpn_in_socket */
int setup_listen_socket(const sockaddr_t *sa) { int nfd; char *addrstr; int option; char *iface; nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP); if(nfd < 0) { ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno)); return -1; } #ifdef FD_CLOEXEC fcntl(nfd, F_SETFD, FD_CLOEXEC); #endif /* Optimize TCP settings */ option = 1; setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); #endif if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) { #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); ifr.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = 0; free(iface); if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) { closesocket(nfd); logger(LOG_ERR, "Can't bind to interface %s: %s", ifr.ifr_ifrn.ifrn_name, strerror(sockerrno)); return -1; } #else logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface"); #endif } if(bind(nfd, &sa->sa, SALEN(sa->sa))) { closesocket(nfd); addrstr = sockaddr2hostname(sa); logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno)); free(addrstr); return -1; } if(listen(nfd, 3)) { closesocket(nfd); logger(LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno)); return -1; } return nfd; }
/* * \fn hip_xmlrpc_getput() * * \param mode determines get or put, app, retry on/off * If retry is off only one attempt should be made, * on means the connect() should keep retrying * \param app string to use in the XML RPC application field * \param server server address and port to connect to * \param key DHT key used for get or put * \param key_len length of DHT key in bytes * \param value DHT value used for put, ptr for storing value for get * \param value_len ptr to length of value buffer, length of get is returned * \param secret secret value used to make put removable * \param secret_len length of secret value * \param ttl time to live in seconds * * \brief Perform the XML RPC GET, PUT, and RM operations. */ int hip_xmlrpc_getput(int mode, char *app, struct sockaddr *server, char *key, int key_len, char *value, int *value_len, char *secret, int secret_len, int ttl) { xmlDocPtr doc = NULL; xmlNodePtr root_node = NULL, node; int len = 0, s, retval = 0; char buff[2048], oper[14]; unsigned char key64[2 * DHT_KEY_SIZE], val64[2 * DHT_VAL_SIZE]; unsigned char tmp[2 * DHT_VAL_SIZE], *xmlbuff = NULL; fd_set read_fdset; struct timeval timeout, now; char *p; unsigned int retry_attempts = 0; struct sockaddr_in src_addr; struct dht_val *dv, rm; SHA_CTX c; __u8 secret_hash[SHA_DIGEST_LENGTH], value_hash[SHA_DIGEST_LENGTH]; int rm_ttl = 0, value_hash_len; int retry = ((mode & 0x00F0) == XMLRPC_MODE_RETRY_ON); if ((key_len > (2 * DHT_KEY_SIZE)) || (*value_len > (2 * DHT_VAL_SIZE))) { return(-1); } /* * support for removable puts */ memset(&rm, 0, sizeof(struct dht_val)); if ((mode & 0x000F) == XMLRPC_MODE_PUT) { /* * produce hashes of the secret and the value, for later removal */ SHA1_Init(&c); SHA1_Update(&c, value, *value_len); SHA1_Final(value_hash, &c); SHA1_Init(&c); SHA1_Update(&c, secret, secret_len); SHA1_Final(secret_hash, &c); /* * check if we already published a record with this key; record * this new secret value and value_hash */ pthread_mutex_lock(&dht_vals_lock); gettimeofday(&now, NULL); dv = lookup_dht_val(key); if (dv) { /* save old secret so we can remove it later below */ memcpy(&rm, &dv, sizeof(struct dht_val)); /* any time left for removing the old record? */ rm_ttl = TDIFF(rm.expire_time, now); } else { dv = insert_dht_val(key); } strncpy(dv->app, app, sizeof(dv->app)); dv->value_hash_len = SHA_DIGEST_LENGTH; memcpy(dv->value_hash, value_hash, SHA_DIGEST_LENGTH); dv->secret_len = secret_len; memcpy(dv->secret, secret, secret_len); dv->expire_time.tv_usec = now.tv_usec; dv->expire_time.tv_sec = now.tv_sec + ttl; pthread_mutex_unlock(&dht_vals_lock); } switch (mode & 0x000F) { case XMLRPC_MODE_PUT: sprintf(oper, "put_removable"); break; case XMLRPC_MODE_GET: sprintf(oper, "get"); break; case XMLRPC_MODE_RM: sprintf(oper, "rm"); break; default: log_(WARN, "Invalid XMLRPC mode given to DHT.\n"); return(-1); } /* * create a new XML document */ doc = xmlNewDoc(BAD_CAST "1.0"); root_node = xmlNewNode(NULL, BAD_CAST "methodCall"); xmlDocSetRootElement(doc, root_node); node = xmlNewChild(root_node, NULL, BAD_CAST "methodName", BAD_CAST oper); node = xmlNewChild(root_node, NULL, BAD_CAST "params", NULL); memset(tmp, 0, sizeof(tmp)); memcpy(tmp, key, key_len); EVP_EncodeBlock(key64, tmp, key_len); xml_new_param(node, "base64", (char *)key64); /* key */ /* log_(NORM, "Doing %s using key(%d)=", * ((mode & 0x000F)==XMLRPC_MODE_PUT) ? "PUT":"GET", key_len); * print_hex(key, key_len); * log_(NORM, " [%s]\n", key64); // */ switch (mode & 0x000F) { case XMLRPC_MODE_PUT: memset(tmp, 0, sizeof(tmp)); memcpy(tmp, value, *value_len); EVP_EncodeBlock(val64, tmp, *value_len); xml_new_param(node, "base64", (char *)val64); /* value */ xml_new_param(node, "string", "SHA"); /* hash type */ memset(tmp, 0, sizeof(tmp)); memcpy(tmp, secret_hash, SHA_DIGEST_LENGTH); EVP_EncodeBlock(val64, tmp, SHA_DIGEST_LENGTH); xml_new_param(node, "base64", (char *)val64); /* secret_hash */ sprintf((char *)tmp, "%d", ttl); xml_new_param(node, "int", (char *)tmp); /* lifetime */ break; case XMLRPC_MODE_GET: xml_new_param(node, "int", "10"); /* maxvals */ xml_new_param(node, "base64", ""); /* placemark */ memset(value, 0, *value_len); break; case XMLRPC_MODE_RM: memset(tmp, 0, sizeof(tmp)); memcpy(tmp, value_hash, SHA_DIGEST_LENGTH); EVP_EncodeBlock(val64, tmp, SHA_DIGEST_LENGTH); xml_new_param(node, "base64", (char *)val64); /* value_hash */ xml_new_param(node, "string", "SHA"); /* hash type */ memset(tmp, 0, sizeof(tmp)); memcpy(tmp, secret, secret_len); EVP_EncodeBlock(val64, tmp, secret_len); xml_new_param(node, "base64", (char *)val64); /* secret */ sprintf((char *)tmp, "%d", ttl); xml_new_param(node, "int", (char *)tmp); /* lifetime */ } xml_new_param(node, "string", app); /* app */ xmlDocDumpFormatMemory(doc, &xmlbuff, &len, 0); /* * Build an HTTP POST and transmit to server */ memset(buff, 0, sizeof(buff)); build_http_post_header(buff, len, server); /* len is XML length above */ memcpy(&buff[strlen(buff)], xmlbuff, len); xmlFree(xmlbuff); len = strlen(buff) + 1; connect_retry: /* Connect and send the XML RPC */ if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { log_(WARN, "DHT connect - socket error: %s\n", strerror(errno)); retval = -1; goto putget_exit; } /* Use the preferred address as source */ memset(&src_addr, 0, sizeof(src_addr)); src_addr.sin_family = AF_INET; src_addr.sin_addr.s_addr = get_preferred_addr(); if (!src_addr.sin_addr.s_addr) { log_(NORM, "No preferred address, deferring DHT!\n"); return(-1); } log_(NORM, "Using source address of %s for DHT %s.\n", logaddr(SA(&src_addr)), oper); fflush(stdout); if (bind(s, SA(&src_addr), SALEN(&src_addr)) < 0) { log_(WARN, "DHT connect - bind error: %s\n", strerror(errno)); } if (g_state != 0) { return(-1); } if (retry && (retry_attempts > 0)) { /* quit after a certain number of retries */ if (retry_attempts >= HCNF.max_retries) { retval = -2; goto putget_exit; } /* wait packet_timeout seconds before retrying */ hip_sleep(HCNF.packet_timeout); } retry_attempts++; if (connect(s, server, SALEN(server)) < 0) { log_(WARN, "DHT server connect error: %s\n", strerror(errno)); closesocket(s); #ifdef __WIN32__ errno = WSAGetLastError(); if (retry && ((errno == WSAETIMEDOUT) || (errno == WSAENETUNREACH))) { goto connect_retry; } #else if (retry && ((errno == ETIMEDOUT) || (errno == EHOSTUNREACH))) { goto connect_retry; } #endif retval = -3; goto putget_exit; } if (send(s, buff, len, 0) != len) { log_(WARN, "DHT sent incorrect number of bytes\n"); retval = -4; goto putget_exit; } xmlFreeDoc(doc); doc = NULL; /* * Receive XML RPC response from server */ FD_ZERO(&read_fdset); FD_SET((unsigned int)s, &read_fdset); /* use longer timeout when retry==TRUE, because we have own thread */ if (retry) { timeout.tv_sec = 3; timeout.tv_usec = 0; } else { timeout.tv_sec = 0; timeout.tv_usec = 300000; /* 300ms */ } if (select(s + 1, &read_fdset, NULL, NULL, &timeout) < 0) { log_(WARN, "DHT select error: %s\n", strerror(errno)); retval = -5; goto putget_exit; } else if (FD_ISSET(s, &read_fdset)) { if ((len = recv(s, buff, sizeof(buff) - 1, 0)) <= 0) { log_(WARN, "DHT error receiving from server: %s\n", strerror(errno)); retval = -6; goto putget_exit; } if (strncmp(buff, "HTTP", 4) != 0) { return(-7); } if ((p = strstr(buff, "Content-Length: ")) == NULL) { return(-8); } else /* advance ptr to Content-Length */ { p += 16; } sscanf(p, "%d", &len); p = strchr(p, '\n') + 3; /* advance to end of line */ retval = hip_xmlrpc_parse_response(mode, p, len, value, value_len); log_(NORM, "DHT server responded with return code %d (%s).\n", retval, hip_xmlrpc_resp_to_str(retval)); } else { /* select timeout */ if (retry) /* XXX testme: retry select instead? */ { goto connect_retry; } retval = -9; } putget_exit: #ifdef __WIN32__ closesocket(s); #else close(s); #endif if (doc != NULL) { xmlFreeDoc(doc); } if (rm_ttl > 0) { value_hash_len = sizeof(rm.value_hash); hip_xmlrpc_getput(((mode & 0x00F0) | XMLRPC_MODE_RM), app, server, key, key_len, (char *)rm.value_hash, &value_hash_len, (char *)rm.secret, secret_len, rm_ttl); } return(retval); }