예제 #1
0
static int is_ipv4_ok(main_server_st *s, struct sockaddr_storage *ip, struct sockaddr_storage *net, struct sockaddr_storage *mask)
{
	struct sockaddr_storage broadcast;
	unsigned i;

	memcpy(&broadcast, net, sizeof(broadcast));
       	for (i=0;i<sizeof(struct in_addr);i++) {
       		SA_IN_U8_P(&broadcast)[i] |= ~(SA_IN_U8_P(&mask)[i]);
	}

	if (ip_lease_exists(s, ip, sizeof(struct sockaddr_in)) != 0 ||
	    ip_cmp(ip, net) == 0 ||
	    ip_cmp(ip, &broadcast) == 0) {
	    return 0;
	}
	return 1;
}
예제 #2
0
파일: ip-lease.c 프로젝트: cernekee/ocserv
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];
	
	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 && c_netmask) {
		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;
		}

		proc->ipv4 = calloc(1, sizeof(*proc->ipv4));
		if (proc->ipv4 == NULL)
			return ERR_MEM;

		/* 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;

        	memcpy(&tmp, &network, sizeof(tmp));
       		((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
       		((struct sockaddr_in*)&tmp)->sin_port = 0;

		memset(&rnd, 0, sizeof(rnd));
		((struct sockaddr_in*)&rnd)->sin_family = AF_INET;
		((struct sockaddr_in*)&rnd)->sin_port = 0;

		do {
			if (max_loops == 0) {
				mslog(s, proc, LOG_ERR, "could not figure out a valid IPv4 IP.");
				ret = ERR_NO_IP;
				goto fail;
			}
			if (max_loops == MAX_IP_TRIES) {
				uint32_t t = hash_any(proc->username, strlen(proc->username), 0);
				memcpy(SA_IN_U8_P(&rnd), &t, 4);
			} else
				gnutls_rnd(GNUTLS_RND_NONCE, SA_IN_U8_P(&rnd), sizeof(struct in_addr));
			max_loops--;

        		if (SA_IN_U8_P(&rnd)[3] == 255) /* broadcast */
	        		bignum_add(SA_IN_U8_P(&rnd), sizeof(struct in_addr), 1);

			/* Mask the random number with the netmask */
        		for (i=0;i<sizeof(struct in_addr);i++) {
        			SA_IN_U8_P(&rnd)[i] &= ~(SA_IN_U8_P(&mask)[i]);
			}

			SA_IN_U8_P(&rnd)[sizeof(struct in_addr)-1] &= 0xFE;

			/* Now add the IP to the masked random number */
        		for (i=0;i<sizeof(struct in_addr);i++)
        			SA_IN_U8_P(&rnd)[i] |= (SA_IN_U8_P(&network)[i]);

 			/* check if it exists in the hash table */
			if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in)) != 0) {
				mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s to '%s'; it is in use.", 
				      human_addr((void*)&rnd, sizeof(struct sockaddr_in), buf, sizeof(buf)), 
				      proc->username);
				continue;
			}

			memcpy(&proc->ipv4->lip, &rnd, sizeof(struct sockaddr_in));
        		proc->ipv4->lip_len = sizeof(struct sockaddr_in);

        		/* RIP = LIP + 1 */
        		memcpy(&tmp, &proc->ipv4->lip, sizeof(struct sockaddr_in));
        		bignum_add(SA_IN_U8_P(&tmp), sizeof(struct in_addr), 1);

 			/* check if it exists in the hash table */
			if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in)) != 0) {
				mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s to '%s'; it is in use.", 
				      human_addr((void*)&tmp, sizeof(struct sockaddr_in), buf, sizeof(buf)), 
				      proc->username);
				continue;
			}

        		memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in));
        		proc->ipv4->rip_len = sizeof(struct sockaddr_in);

        		/* mask the last IP with the netmask */
        		for (i=0;i<sizeof(struct in_addr);i++)
        			SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);

        		/* the result should match the network */
        		if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
        			continue;
        		}

			mslog(s, proc, LOG_DEBUG, "selected IP for '%s': %s", proc->username,
			      human_addr((void*)&proc->ipv4->lip, proc->ipv4->lip_len, buf, sizeof(buf)));
        		
        		if (icmp_ping4(s, (void*)&proc->ipv4->lip, (void*)&proc->ipv4->rip) == 0)
        			break;
                } while(1);
	}

	return 0;

fail:
	free(proc->ipv4);
	proc->ipv4 = NULL;

	return ret;
}
예제 #3
0
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;
	}