summaryrefslogtreecommitdiff
path: root/core/DHT.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/DHT.c')
-rw-r--r--core/DHT.c367
1 files changed, 325 insertions, 42 deletions
diff --git a/core/DHT.c b/core/DHT.c
index 030c578e..58cffdba 100644
--- a/core/DHT.c
+++ b/core/DHT.c
@@ -46,6 +46,12 @@ typedef struct
46 Client_data client_list[MAX_FRIEND_CLIENTS]; 46 Client_data client_list[MAX_FRIEND_CLIENTS];
47 uint32_t lastgetnode; /* time at which the last get_nodes request was sent. */ 47 uint32_t lastgetnode; /* time at which the last get_nodes request was sent. */
48 48
49 /*Symetric NAT hole punching stuff*/
50 uint8_t hole_punching; /*0 if not hole punching, 1 if currently hole punching */
51 uint32_t punching_index;
52 uint32_t punching_timestamp;
53 uint64_t NATping_id;
54 uint32_t NATping_timestamp;
49}Friend; 55}Friend;
50 56
51 57
@@ -78,7 +84,7 @@ static Friend * friends_list;
78static uint16_t num_friends; 84static uint16_t num_friends;
79 85
80/* The list of ip ports along with the ping_id of what we sent them and a timestamp */ 86/* The list of ip ports along with the ping_id of what we sent them and a timestamp */
81#define LPING_ARRAY 128 87#define LPING_ARRAY 256
82 88
83static Pinged pings[LPING_ARRAY]; 89static Pinged pings[LPING_ARRAY];
84 90
@@ -160,10 +166,24 @@ int client_in_nodelist(Node_format * list, uint32_t length, uint8_t * client_id)
160 166
161} 167}
162 168
169/*Return the friend number from the client_id
170 Return -1 if failure, number of friend if success*/
171static int friend_number(uint8_t * client_id)
172{
173 uint32_t i;
174 for(i = 0; i < num_friends; ++i)
175 {
176 if(memcmp(friends_list[i].client_id, client_id, CLIENT_ID_SIZE) == 0) /* Equal */
177 {
178 return i;
179 }
180 }
181 return -1;
182}
163 183
164 184
165/* the number of seconds for a non responsive node to become bad. */ 185/* the number of seconds for a non responsive node to become bad. */
166#define BAD_NODE_TIMEOUT 130 186#define BAD_NODE_TIMEOUT 70
167/* the max number of nodes to send with send nodes. */ 187/* the max number of nodes to send with send nodes. */
168#define MAX_SENT_NODES 8 188#define MAX_SENT_NODES 8
169 189
@@ -809,6 +829,7 @@ int DHT_addfriend(uint8_t * client_id)
809 friends_list = temp; 829 friends_list = temp;
810 memset(&friends_list[num_friends], 0, sizeof(Friend)); 830 memset(&friends_list[num_friends], 0, sizeof(Friend));
811 memcpy(friends_list[num_friends].client_id, client_id, CLIENT_ID_SIZE); 831 memcpy(friends_list[num_friends].client_id, client_id, CLIENT_ID_SIZE);
832 friends_list[num_friends].NATping_id = ((uint64_t)random_int() << 32) + random_int();
812 ++num_friends; 833 ++num_friends;
813 return 0; 834 return 0;
814} 835}
@@ -872,30 +893,6 @@ IP_Port DHT_getfriendip(uint8_t * client_id)
872 893
873 894
874 895
875int DHT_handlepacket(uint8_t * packet, uint32_t length, IP_Port source)
876{
877 switch (packet[0]) {
878 case 0:
879 return handle_pingreq(packet, length, source);
880
881 case 1:
882 return handle_pingres(packet, length, source);
883
884 case 2:
885 return handle_getnodes(packet, length, source);
886
887 case 3:
888 return handle_sendnodes(packet, length, source);
889
890 default:
891 return 1;
892
893 }
894
895 return 0;
896
897}
898
899/* The timeout after which a node is discarded completely. */ 896/* The timeout after which a node is discarded completely. */
900#define Kill_NODE_TIMEOUT 300 897#define Kill_NODE_TIMEOUT 300
901 898
@@ -988,11 +985,6 @@ void doClose() /* tested */
988 985
989 986
990 987
991void doDHT()
992{
993 doClose();
994 doDHTFriends();
995}
996 988
997 989
998 990
@@ -1018,6 +1010,39 @@ int route_packet(uint8_t * client_id, uint8_t * packet, uint32_t length)
1018 return -1; 1010 return -1;
1019} 1011}
1020 1012
1013
1014/* Puts all the different ips returned by the nodes for a friend_num into array ip_portlist
1015 ip_portlist must be at least MAX_FRIEND_CLIENTS big
1016 returns the number of ips returned
1017 return 0 if we are connected to friend or if no ips were found.
1018 returns -1 if no such friend*/
1019static int friend_iplist(IP_Port * ip_portlist, uint16_t friend_num)
1020{
1021 int num_ips = 0;
1022 uint32_t i;
1023 uint32_t temp_time = unix_time();
1024 if(friend_num >= num_friends)
1025 {
1026 return -1;
1027 }
1028 for(i = 0; i < MAX_FRIEND_CLIENTS; ++i)
1029 {
1030 if(friends_list[friend_num].client_list[i].ret_ip_port.ip.i != 0 &&
1031 friends_list[friend_num].client_list[i].ret_timestamp + BAD_NODE_TIMEOUT > temp_time)
1032 /*If ip is not zero and node is good */
1033 {
1034 if(memcmp(friends_list[friend_num].client_list[i].client_id, friends_list[friend_num].client_id, CLIENT_ID_SIZE) == 0 )
1035 {
1036 return 0;
1037 }
1038 ip_portlist[num_ips] = friends_list[friend_num].client_list[i].ret_ip_port;
1039 ++num_ips;
1040 }
1041 }
1042 return num_ips;
1043}
1044
1045
1021/* Send the following packet to everyone who tells us they are connected to friend_id 1046/* Send the following packet to everyone who tells us they are connected to friend_id
1022 returns the number of nodes it sent the packet to */ 1047 returns the number of nodes it sent the packet to */
1023int route_tofriend(uint8_t * friend_id, uint8_t * packet, uint32_t length) 1048int route_tofriend(uint8_t * friend_id, uint8_t * packet, uint32_t length)
@@ -1047,36 +1072,294 @@ int route_tofriend(uint8_t * friend_id, uint8_t * packet, uint32_t length)
1047 return 0; 1072 return 0;
1048} 1073}
1049 1074
1075/* Send the following packet to one random person who tells us they are connected to friend_id
1076 returns the number of nodes it sent the packet to */
1077int routeone_tofriend(uint8_t * friend_id, uint8_t * packet, uint32_t length)
1078{
1079 int num = friend_number(friend_id);
1080 if(num == -1)
1081 {
1082 return 0;
1083 }
1084
1085 IP_Port ip_list[MAX_FRIEND_CLIENTS];
1086 int n = 0;
1087 uint32_t i;
1088 uint32_t temp_time = unix_time();
1089 for(i = 0; i < MAX_FRIEND_CLIENTS; ++i)
1090 {
1091 if(friends_list[num].client_list[i].ret_ip_port.ip.i != 0 &&
1092 friends_list[num].client_list[i].ret_timestamp + BAD_NODE_TIMEOUT > temp_time)
1093 /*If ip is not zero and node is good */
1094 {
1095 ip_list[n] = friends_list[num].client_list[i].ip_port;
1096 ++n;
1097 }
1098 }
1099 if(n < 1)
1100 {
1101 return 0;
1102 }
1103 if(sendpacket(ip_list[rand() % n], packet, length) == length)
1104 {
1105 return 1;
1106 }
1107 return 0;
1108}
1109
1050/* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist 1110/* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist
1051 ip_portlist must be at least MAX_FRIEND_CLIENTS big 1111 ip_portlist must be at least MAX_FRIEND_CLIENTS big
1052 returns the number of ips returned 1112 returns the number of ips returned
1113 return 0 if we are connected to friend or if no ips were found.
1053 returns -1 if no such friend*/ 1114 returns -1 if no such friend*/
1054int friend_ips(IP_Port * ip_portlist, uint8_t * friend_id) 1115int friend_ips(IP_Port * ip_portlist, uint8_t * friend_id)
1055{ 1116{
1056 int num_ips = 0; 1117
1118 uint32_t i;
1119 for(i = 0; i < num_friends; ++i)
1120 {
1121 if(memcmp(friends_list[i].client_id, friend_id, CLIENT_ID_SIZE) == 0) /* Equal */
1122 {
1123 return friend_iplist(ip_portlist, i);
1124 }
1125 }
1126 return -1;
1127}
1128
1129/*BEGINNING OF NAT PUNCHING FUNCTIONS*/
1130
1131int send_NATping(uint8_t * public_key, uint64_t ping_id, uint8_t type)
1132{
1133 uint8_t data[sizeof(uint64_t) + 1];
1134 data[0] = type;
1135 memcpy(data + 1, &ping_id, sizeof(uint64_t));
1136
1137 uint8_t packet[MAX_DATA_SIZE];
1138 int len = create_request(packet, public_key, data, sizeof(uint64_t) + 1, 254); /* 254 is NAT ping request packet id */
1139 if(len == -1)
1140 {
1141 return -1;
1142 }
1143 int num = 0;
1144 if(type == 0)
1145 {
1146 num = route_tofriend(public_key, packet, len);/*If packet is request use many people to route it*/
1147 }
1148 else if(type == 1)
1149 {
1150 num = routeone_tofriend(public_key, packet, len);/*If packet is response use only one person to route it*/
1151 }
1152 if(num == 0)
1153 {
1154 return -1;
1155 }
1156 return num;
1157}
1158
1159
1160/* Handle a recieved ping request for */
1161int handle_NATping(uint8_t * packet, uint32_t length, IP_Port source)
1162{
1163 if(length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING &&
1164 length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
1165 {
1166 return 1;
1167 }
1168 if(memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0)//check if request is for us.
1169 {
1170 uint8_t public_key[crypto_box_PUBLICKEYBYTES];
1171 uint8_t data[MAX_DATA_SIZE];
1172 int len = handle_request(public_key, data, packet, length);
1173 if(len != sizeof(uint64_t) + 1)
1174 {
1175 return 1;
1176 }
1177 uint64_t ping_id;
1178 memcpy(&ping_id, data + 1, sizeof(uint64_t));
1179
1180 int friendnumber = friend_number(public_key);
1181 if(friendnumber == -1)
1182 {
1183 return 1;
1184 }
1185
1186 if(data[0] == 0)
1187 {
1188 send_NATping(public_key, ping_id, 1);/*1 is reply*/
1189 return 0;
1190 }
1191 else if (data[0] == 1)
1192 {
1193 if(friends_list[friendnumber].NATping_id == ping_id)
1194 {
1195 friends_list[friendnumber].NATping_id = ((uint64_t)random_int() << 32) + random_int();
1196 friends_list[friendnumber].hole_punching = 1;
1197 return 0;
1198 }
1199 }
1200 return 1;
1201 }
1202 else//if request is not for us, try routing it.
1203 {
1204 if(route_packet(packet + 1, packet, length) == length)
1205 {
1206 return 0;
1207 }
1208 }
1209 return 0;
1210}
1211
1212/*Get the most common ip in the ip_portlist
1213 Only return ip if it appears in list min_num or more
1214 len must not be bigger than MAX_FRIEND_CLIENTS
1215 return ip of 0 if failure */
1216static IP NAT_commonip(IP_Port * ip_portlist, uint16_t len, uint16_t min_num)
1217{
1218 IP zero = {{0}};
1219 if(len > MAX_FRIEND_CLIENTS)
1220 {
1221 return zero;
1222 }
1223
1057 uint32_t i, j; 1224 uint32_t i, j;
1225 uint16_t numbers[MAX_FRIEND_CLIENTS] = {0};
1226 for(i = 0; i < len; ++i)
1227 {
1228 for(j = 0; j < len; ++j)
1229 {
1230 if(ip_portlist[i].ip.i == ip_portlist[j].ip.i)
1231 {
1232 ++numbers[i];
1233 }
1234 }
1235 if(numbers[i] >= min_num)
1236 {
1237 return ip_portlist[i].ip;
1238 }
1239 }
1240 return zero;
1241}
1242
1243/*Return all the ports for one ip in a list
1244 portlist must be at least len long
1245 where len is the length of ip_portlist
1246 returns the number of ports and puts the list of ports in portlist*/
1247static uint16_t NAT_getports(uint16_t * portlist, IP_Port * ip_portlist, uint16_t len, IP ip)
1248{
1249 uint32_t i;
1250 uint16_t num = 0;
1251 for(i = 0; i < len; ++i)
1252 {
1253 if(ip_portlist[i].ip.i == ip.i)
1254 {
1255 portlist[num] = ntohs(ip_portlist[i].port);
1256 ++num;
1257 }
1258 }
1259 return num;
1260}
1261
1262#define MAX_PUNCHING_PORTS 32
1263
1264static void punch_holes(IP ip, uint16_t * port_list, uint16_t numports, uint16_t friend_num)
1265{
1266 if(numports > MAX_FRIEND_CLIENTS || numports == 0)
1267 {
1268 return;
1269 }
1270 uint32_t i;
1271 uint32_t top = friends_list[friend_num].punching_index + MAX_PUNCHING_PORTS;
1272 for(i = friends_list[friend_num].punching_index; i != top; i++)
1273 {
1274 /*TODO: improve port guessing algorithm*/
1275 uint16_t port = port_list[(i/2) % numports] + (i/(2*numports))*((i % 2) ? -1 : 1);
1276 IP_Port pinging = {ip, htons(port)};
1277 pingreq(pinging, friends_list[friend_num].client_id);
1278 }
1279 friends_list[friend_num].punching_index = i;
1280}
1281
1282/*Interval in seconds between punching attempts*/
1283#define PUNCH_INTERVAL 10
1284
1285static void doNAT()
1286{
1287 uint32_t i;
1058 uint32_t temp_time = unix_time(); 1288 uint32_t temp_time = unix_time();
1059 for(i = 0; i < num_friends; ++i) 1289 for(i = 0; i < num_friends; ++i)
1060 { 1290 {
1061 if(memcmp(friends_list[i].client_id, friend_id, CLIENT_ID_SIZE) == 0) /* Equal */ 1291 IP_Port ip_list[MAX_FRIEND_CLIENTS];
1292 int num = friend_iplist(ip_list, i);
1293 /*If we are connected to friend or if friend is not online don't try to hole punch with him*/
1294 if(num < MAX_FRIEND_CLIENTS/2)
1062 { 1295 {
1063 for(j = 0; j < MAX_FRIEND_CLIENTS; ++j) 1296 continue;
1297 }
1298 if(friends_list[i].hole_punching != 1)
1299 {
1300 if(friends_list[i].NATping_timestamp + PUNCH_INTERVAL < temp_time)
1064 { 1301 {
1065 if(friends_list[i].client_list[j].ret_ip_port.ip.i != 0 && 1302 send_NATping(friends_list[i].client_id, friends_list[i].NATping_id, 0); /*0 is request*/
1066 friends_list[i].client_list[j].ret_timestamp + BAD_NODE_TIMEOUT > temp_time) 1303 friends_list[i].NATping_timestamp = temp_time;
1067 /*If ip is not zero and node is good */
1068 {
1069 ip_portlist[num_ips] = friends_list[i].client_list[j].ret_ip_port;
1070 ++num_ips;
1071 }
1072 } 1304 }
1073 return num_ips;
1074 } 1305 }
1306 else if(friends_list[i].punching_timestamp + PUNCH_INTERVAL < temp_time)
1307 {
1308 IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS/2);
1309 if(ip.i == 0)
1310 {
1311 continue;
1312 }
1313 uint16_t port_list[MAX_FRIEND_CLIENTS];
1314 uint16_t numports = NAT_getports(port_list, ip_list, num, ip);
1315 punch_holes(ip, port_list, numports, i);
1316
1317 friends_list[i].punching_timestamp = temp_time;
1318 friends_list[i].hole_punching = 0;
1319 }
1320 }
1321}
1322
1323/*END OF NAT PUNCHING FUNCTIONS*/
1324
1325
1326int DHT_handlepacket(uint8_t * packet, uint32_t length, IP_Port source)
1327{
1328 switch (packet[0]) {
1329 case 0:
1330 return handle_pingreq(packet, length, source);
1331
1332 case 1:
1333 return handle_pingres(packet, length, source);
1334
1335 case 2:
1336 return handle_getnodes(packet, length, source);
1337
1338 case 3:
1339 return handle_sendnodes(packet, length, source);
1340
1341 case 254:
1342 return handle_NATping(packet, length, source);
1343
1344 default:
1345 return 1;
1075 1346
1076 } 1347 }
1348
1077 return 0; 1349 return 0;
1350
1078} 1351}
1079 1352
1353
1354void doDHT()
1355{
1356 doClose();
1357 doDHTFriends();
1358 doNAT();
1359}
1360
1361
1362
1080/* get the size of the DHT (for saving) */ 1363/* get the size of the DHT (for saving) */
1081uint32_t DHT_size() 1364uint32_t DHT_size()
1082{ 1365{