static ssize_t pull_func (gnutls_transport_ptr_t p, void *data, size_t size) { priv_data_st *priv = p; struct sockaddr_in cli_addr; socklen_t cli_addr_size; char buffer[64]; int ret; cli_addr_size = sizeof (cli_addr); ret = recvfrom (priv->fd, data, size, 0, (struct sockaddr *) &cli_addr, &cli_addr_size); if (ret == -1) return ret; if (cli_addr_size == priv->cli_addr_size && memcmp (&cli_addr, priv->cli_addr, sizeof (cli_addr)) == 0) return ret; printf ("Denied connection from %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof (cli_addr), buffer, sizeof (buffer))); gnutls_transport_set_errno (priv->session, EAGAIN); return -1; }
int get_ip_leases(main_server_st* s, struct proc_st* proc) { int ret; char buf[128]; if (proc->ipv4 == NULL) { ret = get_ipv4_lease(s, proc); if (ret < 0) return ret; if (proc->ipv4) { if (htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4) == 0) { mslog(s, proc, LOG_ERR, "could not add IPv4 lease to hash table."); return -1; } } } if (proc->ipv6 == NULL) { ret = get_ipv6_lease(s, proc); if (ret < 0) return ret; if (proc->ipv6) { if (htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6) == 0) { mslog(s, proc, LOG_ERR, "could not add IPv6 lease to hash table."); return -1; } } } if (proc->ipv4 == 0 && proc->ipv6 == 0) { mslog(s, proc, LOG_ERR, "no IPv4 or IPv6 addresses are configured. Cannot obtain lease."); return -1; } if (proc->ipv4) mslog(s, proc, LOG_INFO, "assigned IPv4 to '%s': %s", proc->username, human_addr((void*)&proc->ipv4->rip, proc->ipv4->rip_len, buf, sizeof(buf))); if (proc->ipv6) mslog(s, proc, LOG_INFO, "assigned IPv6 to '%s': %s", proc->username, human_addr((void*)&proc->ipv6->rip, proc->ipv6->rip_len, buf, sizeof(buf))); return 0; }
_mslog(const main_server_st * s, const struct proc_st* proc, int priority, const char *fmt, ...) { char buf[512]; char ipbuf[128]; const char* ip = NULL; va_list args; if (priority == LOG_DEBUG && s->perm_config->debug < 3) return; if (priority == LOG_HTTP_DEBUG) { if (s->perm_config->debug < DEBUG_HTTP) return; else priority = LOG_DEBUG; } else if (priority == LOG_TRANSFER_DEBUG) { if (s->perm_config->debug < DEBUG_TRANSFERRED) return; else priority = LOG_DEBUG; } if (proc) { ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, ipbuf, sizeof(ipbuf)); } va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (ip) { if (proc->username[0] == 0) syslog(priority, "main: %s %s", ip, buf); else syslog(priority, "main[%s]: %s %s", proc->username, ip, buf); } else { syslog(priority, "main: %s", buf); } return; }
void udp_server(const char* name, int port, int mtu) { int sock, ret; struct sockaddr_in cli_addr; socklen_t cli_addr_size; char buffer[MAX_BUFFER]; priv_data_st priv; gnutls_session_t session; gnutls_datum_t cookie_key; gnutls_dtls_prestate_st prestate; unsigned char sequence[8]; ret = gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE); if (ret < 0) { fprintf(stderr, "Cannot generate key\n"); exit(1); } ret = listen_socket (name, port, SOCK_DGRAM); if (ret < 0) { fprintf(stderr, "Cannot listen\n"); exit (1); } for (;;) { printf("Waiting for connection...\n"); sock = wait_for_connection(); if (sock < 0) continue; cli_addr_size = sizeof(cli_addr); ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size); if (ret > 0) { memset(&prestate, 0, sizeof(prestate)); ret = gnutls_dtls_cookie_verify(&cookie_key, &cli_addr, sizeof(cli_addr), buffer, ret, &prestate); if (ret < 0) /* cookie not valid */ { priv_data_st s; memset(&s,0,sizeof(s)); s.fd = sock; s.cli_addr = (void*)&cli_addr; s.cli_addr_size = sizeof(cli_addr); printf("Sending hello verify request to %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); gnutls_dtls_cookie_send(&cookie_key, &cli_addr, sizeof(cli_addr), &prestate, (gnutls_transport_ptr_t)&s, push_func); /* discard peeked data*/ recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&cli_addr, &cli_addr_size); continue; } printf ("Accepted connection from %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof (buffer))); } else continue; session = initialize_session(1); gnutls_dtls_prestate_set(session, &prestate); if (mtu) gnutls_dtls_set_mtu(session, mtu); priv.session = session; priv.fd = sock; priv.cli_addr = (struct sockaddr *)&cli_addr; priv.cli_addr_size = sizeof(cli_addr); gnutls_transport_set_ptr (session, &priv); gnutls_transport_set_push_function (session, push_func); gnutls_transport_set_pull_function (session, pull_func); gnutls_transport_set_pull_timeout_function (session, pull_timeout_func); do { ret = gnutls_handshake(session); } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret)); gnutls_deinit(session); continue; } for(;;) { do { ret = gnutls_record_recv_seq(session, buffer, MAX_BUFFER, sequence); } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret == GNUTLS_E_REHANDSHAKE) { fprintf (stderr, "*** Received hello message\n"); do { ret = gnutls_handshake (session); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); if (ret == 0) continue; } if (ret < 0) { fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret)); break; } if (ret == 0) { printf("EOF\n\n"); break; } buffer[ret] = 0; printf("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence[0], sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], sequence[6], sequence[7], buffer); if (check_command(session, buffer) == 0) { /* reply back */ ret = gnutls_record_send(session, buffer, ret); if (ret < 0) { fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret)); break; } } } } gnutls_deinit(session); }
int main (void) { int listen_sd; int sock, ret; struct sockaddr_in sa_serv; struct sockaddr_in cli_addr; socklen_t cli_addr_size; gnutls_session_t session; char buffer[MAX_BUFFER]; priv_data_st priv; gnutls_datum_t cookie_key; gnutls_dtls_prestate_st prestate; int mtu = 1400; unsigned char sequence[8]; /* this must be called once in the program */ gnutls_global_init (); gnutls_certificate_allocate_credentials (&x509_cred); gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM); ret = gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM); if (ret < 0) { printf("No certificate or key were found\n"); exit(1); } generate_dh_params (); gnutls_certificate_set_dh_params (x509_cred, dh_params); gnutls_priority_init (&priority_cache, "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE", NULL); gnutls_key_generate (&cookie_key, GNUTLS_COOKIE_KEY_SIZE); /* Socket operations */ listen_sd = socket (AF_INET, SOCK_DGRAM, 0); memset (&sa_serv, '\0', sizeof (sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons (PORT); { /* DTLS requires the IP don't fragment (DF) bit to be set */ #if defined(IP_DONTFRAG) int optval = 1; setsockopt (listen_sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &optval, sizeof (optval)); #elif defined(IP_MTU_DISCOVER) int optval = IP_PMTUDISC_DO; setsockopt(listen_sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void*) &optval, sizeof (optval)); #endif } bind (listen_sd, (struct sockaddr *) &sa_serv, sizeof (sa_serv)); printf ("UDP server ready. Listening to port '%d'.\n\n", PORT); for (;;) { printf ("Waiting for connection...\n"); sock = wait_for_connection (listen_sd); if (sock < 0) continue; cli_addr_size = sizeof (cli_addr); ret = recvfrom (sock, buffer, sizeof (buffer), MSG_PEEK, (struct sockaddr *) &cli_addr, &cli_addr_size); if (ret > 0) { memset (&prestate, 0, sizeof (prestate)); ret = gnutls_dtls_cookie_verify (&cookie_key, &cli_addr, sizeof (cli_addr), buffer, ret, &prestate); if (ret < 0) /* cookie not valid */ { priv_data_st s; memset (&s, 0, sizeof (s)); s.fd = sock; s.cli_addr = (void *) &cli_addr; s.cli_addr_size = sizeof (cli_addr); printf ("Sending hello verify request to %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof (cli_addr), buffer, sizeof (buffer))); gnutls_dtls_cookie_send (&cookie_key, &cli_addr, sizeof (cli_addr), &prestate, (gnutls_transport_ptr_t) & s, push_func); /* discard peeked data */ recvfrom (sock, buffer, sizeof (buffer), 0, (struct sockaddr *) &cli_addr, &cli_addr_size); usleep (100); continue; } printf ("Accepted connection from %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof (cli_addr), buffer, sizeof (buffer))); } else continue; session = initialize_tls_session (); gnutls_dtls_prestate_set (session, &prestate); gnutls_dtls_set_mtu (session, mtu); priv.session = session; priv.fd = sock; priv.cli_addr = (struct sockaddr *) &cli_addr; priv.cli_addr_size = sizeof (cli_addr); gnutls_transport_set_ptr (session, &priv); gnutls_transport_set_push_function (session, push_func); gnutls_transport_set_pull_function (session, pull_func); gnutls_transport_set_pull_timeout_function (session, pull_timeout_func); do { ret = gnutls_handshake (session); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); if (ret < 0) { fprintf (stderr, "Error in handshake(): %s\n", gnutls_strerror (ret)); gnutls_deinit (session); continue; } printf ("- Handshake was completed\n"); for (;;) { do { ret = gnutls_record_recv_seq (session, buffer, MAX_BUFFER, sequence); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { fprintf (stderr, "Error in recv(): %s\n", gnutls_strerror (ret)); break; } if (ret == 0) { printf ("EOF\n\n"); break; } buffer[ret] = 0; printf ("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence[0], sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], sequence[6], sequence[7], buffer); /* reply back */ ret = gnutls_record_send (session, buffer, ret); if (ret < 0) { fprintf (stderr, "Error in send(): %s\n", gnutls_strerror (ret)); break; } } gnutls_bye (session, GNUTLS_SHUT_WR); gnutls_deinit (session); } close (listen_sd); gnutls_certificate_free_credentials (x509_cred); gnutls_priority_deinit (priority_cache); gnutls_global_deinit (); return 0; }
static int get_ipv6_lease(main_server_st* s, struct proc_st* proc) { struct sockaddr_storage tmp, mask, network, rnd; unsigned i, max_loops = MAX_IP_TRIES; int ret; const char* c_network, *c_netmask; char buf[64]; if (proc->config.ipv6_network && proc->config.ipv6_netmask) { c_network = proc->config.ipv6_network; c_netmask = proc->config.ipv6_netmask; } else { c_network = s->config->network.ipv6; c_netmask = s->config->network.ipv6_netmask; } if (c_network && c_netmask) { ret = inet_pton(AF_INET6, c_network, SA_IN6_P(&network)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); return -1; } ret = inet_pton(AF_INET6, c_netmask, SA_IN6_P(&mask)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); return -1; } proc->ipv6 = calloc(1, sizeof(*proc->ipv6)); if (proc->ipv6 == NULL) return ERR_MEM; /* mask the network */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]); ((struct sockaddr_in6*)&network)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&network)->sin6_port = 0; memcpy(&tmp, &network, sizeof(tmp)); ((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&tmp)->sin6_port = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_port = AF_INET6; do { if (max_loops == 0) { mslog(s, NULL, LOG_ERR, "could not figure out a valid IPv6 IP."); ret = ERR_NO_IP; goto fail; } if (max_loops == MAX_IP_TRIES) { uint32_t t = hash_any(proc->username, strlen(proc->username), 0); memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr)); memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, &t, 4); } else gnutls_rnd(GNUTLS_RND_NONCE, SA_IN6_U8_P(&rnd), sizeof(struct in6_addr)); max_loops--; /* Mask the random number with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] &= ~(SA_IN6_U8_P(&mask)[i]); SA_IN6_U8_P(&rnd)[sizeof(struct in6_addr)-1] &= 0xFE; /* Now add the network to the masked random number */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] |= (SA_IN6_U8_P(&network)[i]); /* check if it exists in the hash table */ if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign local IP %s to '%s'; it is in use.", human_addr((void*)&rnd, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->lip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len); /* RIP = LIP + 1 */ memcpy(&tmp, &proc->ipv6->lip, proc->ipv6->rip_len); bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1); /* check if it exists in the hash table */ if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s to '%s'; it is in use.", human_addr((void*)&tmp, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->rip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len); /* mask the last IP with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]); /* the result should match the network */ if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) { continue; } mslog(s, proc, LOG_DEBUG, "selected IP for '%s': %s", proc->username, human_addr((void*)&proc->ipv6->lip, proc->ipv6->lip_len, buf, sizeof(buf))); if (icmp_ping6(s, (void*)&proc->ipv6->lip, (void*)&proc->ipv6->rip) == 0) break; } while(1); } return 0; fail: free(proc->ipv6); proc->ipv6 = NULL; return ret; }
static int get_ipv4_lease(main_server_st* s, struct proc_st* proc) { struct sockaddr_storage tmp, mask, network, rnd; unsigned i; unsigned max_loops = MAX_IP_TRIES; int ret; const char* c_network, *c_netmask; char buf[64]; /* Our IP accounting */ if (proc->config.ipv4_network && proc->config.ipv4_netmask) { c_network = proc->config.ipv4_network; c_netmask = proc->config.ipv4_netmask; } else { c_network = s->config->network.ipv4; c_netmask = s->config->network.ipv4_netmask; } if (c_network == NULL || c_netmask == NULL) { mslog(s, NULL, LOG_DEBUG, "there is no IPv4 network assigned"); return 0; } ret = inet_pton(AF_INET, c_network, SA_IN_P(&network)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); return -1; } ret = inet_pton(AF_INET, c_netmask, SA_IN_P(&mask)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); return -1; } /* mask the network (just in case it is wrong) */ for (i=0;i<sizeof(struct in_addr);i++) SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]); ((struct sockaddr_in*)&network)->sin_family = AF_INET; ((struct sockaddr_in*)&network)->sin_port = 0; if (proc->config.explicit_ipv4) { /* if an explicit IP is given for that client, then * do implicit IP accounting. Require the address * to be odd, so we use the next even address as PtP. */ ret = inet_pton(AF_INET, proc->config.explicit_ipv4, SA_IN_P(&tmp)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv4); return -1; } proc->ipv4 = talloc_zero(proc, struct ip_lease_st); if (proc->ipv4 == NULL) return ERR_MEM; ((struct sockaddr_in*)&tmp)->sin_family = AF_INET; ((struct sockaddr_in*)&tmp)->sin_port = 0; memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in)); proc->ipv4->rip_len = sizeof(struct sockaddr_in); if (is_ipv4_ok(s, &proc->ipv4->rip, &network, &mask) == 0) { mslog(s, proc, LOG_DEBUG, "cannot assign explicit IP %s; it is in use or invalid", human_addr((void*)&tmp, sizeof(struct sockaddr_in), buf, sizeof(buf))); ret = ERR_NO_IP; goto fail; } /* LIP = network address + 1 */ memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in)); proc->ipv4->lip_len = sizeof(struct sockaddr_in); SA_IN_U8_P(&proc->ipv4->lip)[3] |= 1; if (ip_cmp(&proc->ipv4->lip, &proc->ipv4->rip) == 0) { mslog(s, NULL, LOG_ERR, "cannot assign explicit IP %s; network: %s", proc->config.explicit_ipv4, c_network); ret = ERR_NO_IP; goto fail; } return 0; }