diff --git a/src/iodined.c b/src/iodined.c index 1e9eeac..e5a8393 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -791,6 +791,8 @@ main(int argc, char **argv) int port; int mtu; int skipipconfig; + int netmask; + int created_users; username = NULL; newroot = NULL; @@ -805,6 +807,7 @@ main(int argc, char **argv) check_ip = 1; skipipconfig = 0; debug = 0; + netmask = 27; b32 = get_base32_encoder(); @@ -954,6 +957,10 @@ main(int argc, char **argv) warnx("Bad IP address to return as nameserver.\n"); usage(); } + if (netmask > 30 || netmask < 8) { + warnx("Bad netmask (%d bits). Use 8-30 bits.\n", netmask); + usage(); + } if (strlen(password) == 0) read_password(password, sizeof(password)); @@ -970,8 +977,13 @@ main(int argc, char **argv) goto cleanup3; my_mtu = mtu; - init_users(my_ip); + created_users = init_users(my_ip, netmask); + + if (created_users < USERS) { + printf("Limiting to %d simultaneous users because of netmask /%d\n", + created_users, netmask); + } printf("Listening to dns for domain %s\n", topdomain); if (foreground == 0) diff --git a/src/user.c b/src/user.c index 1cda64b..26d49b8 100644 --- a/src/user.c +++ b/src/user.c @@ -35,17 +35,49 @@ struct user users[USERS]; -void -init_users(in_addr_t my_ip) +int +init_users(in_addr_t my_ip, int netbits) { int i; + int skip = 0; char newip[16]; + int created_users = 0; + + int maxusers; + + in_addr_t netmask = 0; + struct in_addr net; + struct in_addr ipstart; + + for (i = 0; i < netbits; i++) { + netmask = (netmask << 1) | 1; + } + netmask <<= (32 - netbits); + net.s_addr = htonl(netmask); + ipstart.s_addr = my_ip & net.s_addr; + + maxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */ memset(users, 0, USERS * sizeof(struct user)); for (i = 0; i < USERS; i++) { + in_addr_t ip; users[i].id = i; - snprintf(newip, sizeof(newip), "0.0.0.%d", i + 1); - users[i].tun_ip = my_ip + inet_addr(newip);; + snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1); + ip = ipstart.s_addr + inet_addr(newip); + if (ip == my_ip && skip == 0) { + /* This IP was taken by iodined */ + skip++; + snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1); + ip = ipstart.s_addr + inet_addr(newip); + } + users[i].tun_ip = ip; + net.s_addr = ip; + if (maxusers-- < 1) { + users[i].disabled = 1; + } else { + users[i].disabled = 0; + created_users++; + } users[i].inpacket.len = 0; users[i].inpacket.offset = 0; users[i].outpacket.len = 0; @@ -53,6 +85,8 @@ init_users(in_addr_t my_ip) users[i].out_acked_seqno = 0; users[i].out_acked_fragment = 0; } + + return created_users; } int @@ -63,7 +97,8 @@ users_waiting_on_reply() ret = 0; for (i = 0; i < USERS; i++) { - if (users[i].active && users[i].last_pkt + 60 > time(NULL) && + if (users[i].active && !users[i].disabled && + users[i].last_pkt + 60 > time(NULL) && users[i].q.id != 0) { ret++; } @@ -80,7 +115,8 @@ find_user_by_ip(uint32_t ip) ret = -1; for (i = 0; i < USERS; i++) { - if (users[i].active && users[i].last_pkt + 60 > time(NULL) && + if (users[i].active && !users[i].disabled && + users[i].last_pkt + 60 > time(NULL) && ip == users[i].tun_ip) { ret = i; break; @@ -99,7 +135,8 @@ all_users_waiting_to_send() ret = 1; now = time(NULL); for (i = 0; i < USERS; i++) { - if (users[i].active && users[i].last_pkt + 60 > now && + if (users[i].active && !users[i].disabled && + users[i].last_pkt + 60 > now && users[i].outpacket.len == 0) { ret = 0; break; @@ -115,7 +152,7 @@ find_available_user() int i; for (i = 0; i < USERS; i++) { /* Not used at all or not used in one minute */ - if (!users[i].active || users[i].last_pkt + 60 < time(NULL)) { + if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) { users[i].active = 1; users[i].last_pkt = time(NULL); ret = i; diff --git a/src/user.h b/src/user.h index e877524..caee959 100644 --- a/src/user.h +++ b/src/user.h @@ -22,6 +22,7 @@ struct user { char id; int active; + int disabled; time_t last_pkt; int seed; in_addr_t tun_ip; @@ -36,7 +37,7 @@ struct user { extern struct user users[USERS]; -void init_users(in_addr_t); +int init_users(in_addr_t, int); int users_waiting_on_reply(); int find_user_by_ip(uint32_t); int all_users_waiting_to_send(); diff --git a/tests/user.c b/tests/user.c index 5514fd8..5983717 100644 --- a/tests/user.c +++ b/tests/user.c @@ -34,7 +34,7 @@ START_TEST(test_init_users) int i; ip = inet_addr("127.0.0.1"); - init_users(ip); + init_users(ip, 27); for (i = 0; i < USERS; i++) { fail_unless(users[i].id == i); fail_unless(users[i].q.id == 0); @@ -51,7 +51,7 @@ START_TEST(test_users_waiting) in_addr_t ip; ip = inet_addr("127.0.0.1"); - init_users(ip); + init_users(ip, 27); fail_unless(users_waiting_on_reply() == 0); @@ -75,7 +75,7 @@ START_TEST(test_find_user_by_ip) unsigned int testip; ip = inet_addr("127.0.0.1"); - init_users(ip); + init_users(ip, 27); testip = (unsigned int) inet_addr("10.0.0.1"); fail_unless(find_user_by_ip(testip) == -1); @@ -100,7 +100,7 @@ START_TEST(test_all_users_waiting_to_send) in_addr_t ip; ip = inet_addr("127.0.0.1"); - init_users(ip); + init_users(ip, 27); fail_unless(all_users_waiting_to_send() == 1); @@ -124,7 +124,7 @@ START_TEST(test_find_available_user) int i; ip = inet_addr("127.0.0.1"); - init_users(ip); + init_users(ip, 27); for (i = 0; i < USERS; i++) { fail_unless(find_available_user() == i); @@ -146,6 +146,34 @@ START_TEST(test_find_available_user) } END_TEST +START_TEST(test_find_available_user_small_net) +{ + in_addr_t ip; + int i; + + ip = inet_addr("127.0.0.1"); + init_users(ip, 29); /* this should result in 5 enabled users */ + + for (i = 0; i < 5; i++) { + fail_unless(find_available_user() == i); + } + + for (i = 0; i < USERS; i++) { + fail_unless(find_available_user() == -1); + } + + users[3].active = 0; + + fail_unless(find_available_user() == 3); + fail_unless(find_available_user() == -1); + + users[3].last_pkt = 55; + + fail_unless(find_available_user() == 3); + fail_unless(find_available_user() == -1); +} +END_TEST + TCase * test_user_create_tests() { @@ -157,6 +185,7 @@ test_user_create_tests() tcase_add_test(tc, test_find_user_by_ip); tcase_add_test(tc, test_all_users_waiting_to_send); tcase_add_test(tc, test_find_available_user); + tcase_add_test(tc, test_find_available_user_small_net); return tc; }