12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709 |
- /* This file is part of Netsukuku
- * (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
- *
- * This source code is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License,
- * or (at your option) any later version.
- *
- * This source code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * Please refer to the GNU Public License for more details.
- *
- * You should have received a copy of the GNU Public License along with
- * this source code; if not, write to:
- * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * --
- *
- * hook.c:
- * This is code which handles the hooking of a new node in netsukuku, or the
- * creation of a new gnode.
- */
-
- #include "includes.h"
-
- #include "common.h"
- #include "libnetlink.h"
- #include "ll_map.h"
- #include "inet.h"
- #include "if.h"
- #include "krnl_route.h"
- #include "iptunnel.h"
- #include "endianness.h"
- #include "bmap.h"
- #include "route.h"
- #include "request.h"
- #include "pkts.h"
- #include "tracer.h"
- #include "qspn.h"
- #include "hook.h"
- #include "rehook.h"
- #include "radar.h"
- #include "netsukuku.h"
- #include "common.h"
-
- int free_the_tmp_cur_node;
- int we_are_rehooking; /* 1 if it is true */
-
- void hook_reset(void);
-
- /*
- * hook_fill_rq
- *
- * It's just a wrapper to rnl_fill_rq().
- */
- int
- hook_fill_rq(map_node * dst_rnode, PACKET * pkt, u_char rq)
- {
- if (rnl_fill_rq(dst_rnode, pkt) < 0)
- return -1;
-
- if (server_opt.dbg_lvl) {
- const char *ntop;
- ntop = inet_to_str(pkt->to);
- debug(DBG_INSANE, "Quest %s to %s", rq_to_str(rq), ntop);
- }
-
- return 0;
- }
-
-
- /*
- * verify_free_nodes_hdr: verifies the validity of the `fn_hdr'
- * free_nodes_hdr. `to' is the ip of the node which sent the
- * put_free_nodes reply.
- * If the header is valid 0 is returned.
- */
- int
- verify_free_nodes_hdr(inet_prefix * to, struct free_nodes_hdr *fn_hdr)
- {
- quadro_group qg_a, qg_b;
- inet_prefix ipstart;
-
- if (fn_hdr->max_levels > FAMILY_LVLS || !fn_hdr->level)
- return 1;
-
- if (fn_hdr->level >= fn_hdr->max_levels)
- return 1;
-
- /* If fn_hdr->ipstart != `to' there is an error */
- inet_setip(&ipstart, (u_int *) fn_hdr->ipstart, my_family);
- iptoquadg(ipstart, me.ext_map, &qg_a, QUADG_GID);
- iptoquadg(*to, me.ext_map, &qg_b, QUADG_GID);
- if (quadg_gids_cmp(qg_a, qg_b, fn_hdr->level))
- return 1;
-
- if (fn_hdr->nodes <= 0 || fn_hdr->nodes == (MAXGROUPNODE - 1))
- return 1;
-
- return 0;
- }
-
- /*\
- * * * put/get free_nodes * *
- \*/
-
- /*
- * get_free_nodes
- *
- * It send the GET_FREE_NODES request, used to retrieve the free_nodes pkt
- * (see hook.h), to rnode `dst_rnode'.
- * `fn_hdr' is the header of the received free_nodes packet.
- * `nodes' must be an u_char array with at least MAXGROUPNODES members. All the
- * members that go from `free_nodes[0]' to `free_nodes[fn_hdr.nodes]' will be
- * filled with the gids of the received free nodes.
- * -1 is returned if `to' said its quadro_group is full or if a generic error
- * occurred. In this case it is advised to ask to get the free_nodes list from
- * another rnode.
- * If -2 is returned, the whole Netsukuku net is full, so desist to retry, or
- * drop down your neighbors.
- */
- int
- get_free_nodes(map_node * dst_rnode,
- struct free_nodes_hdr *fn_hdr, u_char * nodes)
- {
- PACKET pkt, rpkt;
- ssize_t err;
- int ret = 0, e, i;
- char *buf = 0;
-
- setzero(&pkt, sizeof(PACKET));
- setzero(&rpkt, sizeof(PACKET));
-
- hook_fill_rq(dst_rnode, &pkt, GET_FREE_NODES) < 0 && _return(-1);
- pkt_addtimeout(&pkt, HOOK_RQ_TIMEOUT, 1, 0);
-
- err =
- rnl_send_rq(dst_rnode, &pkt, 0, GET_FREE_NODES, 0, PUT_FREE_NODES,
- 1, &rpkt);
- if (err < 0) {
- if (rpkt.hdr.sz && (u_char) (*rpkt.msg) == E_NTK_FULL)
- ERROR_FINISH(ret, -2, finish);
- ERROR_FINISH(ret, -1, finish);
- }
-
- ints_network_to_host(rpkt.msg, free_nodes_hdr_iinfo);
- memcpy(fn_hdr, rpkt.msg, sizeof(struct free_nodes_hdr));
-
- if (verify_free_nodes_hdr(&pkt.to, fn_hdr)) {
- error("Malformed PUT_FREE_NODES request hdr from %s",
- inet_to_str(pkt.to));
- ERROR_FINISH(ret, -1, finish);
- }
-
- fn_hdr->nodes++;
-
- buf = rpkt.msg + sizeof(struct free_nodes_hdr);
-
- for (i = 0, e = 0; i < MAXGROUPNODE; i++) {
- if (TEST_BIT(buf, i)) {
- nodes[e] = i;
- e++;
- }
- }
-
- debug(DBG_NORMAL, "Received %d free %s", fn_hdr->nodes,
- fn_hdr->level == 1 ? "nodes" : "gnodes");
- finish:
- pkt_free(&pkt, 0);
- pkt_free(&rpkt, 0);
- return ret;
- }
-
- /*
- * put_free_nodes: It sends a free_nodes pkt to rq_pkt.from. To see what's a
- * free_nodes pkt go in hook.h.
- */
- int
- put_free_nodes(PACKET rq_pkt)
- {
- struct fn_pkt {
- struct free_nodes_hdr fn_hdr;
- u_char free_nodes[MAXGROUPNODE >> 3];
- } _PACKED_ fn_pkt;
-
- PACKET pkt;
- int ret = 0, i, e = 0, links;
- ssize_t err, pkt_sz;
- u_char level, err_reply;
- const char *ntop;
- char *p = 0;
-
- ntop = inet_to_str(rq_pkt.from);
-
- setzero(&pkt, sizeof(PACKET));
- pkt_addto(&pkt, &rq_pkt.from);
- pkt_addport(&pkt, ntk_tcp_port);
- pkt_addsk(&pkt, my_family, rq_pkt.sk, rq_pkt.sk_type);
- pkt_add_dev(&pkt, rq_pkt.dev, 1);
- pkt_addcompress(&pkt);
-
- /* We search in each level a gnode which is not full. */
- for (level = 1, e = 0; level < me.cur_quadg.levels; level++) {
- if (!(me.cur_quadg.gnode[_EL(level)]->flags & GMAP_FULL)) {
- e = 1;
- break;
- }
- }
- if (!e) {
- if (me.ext_map[_EL(me.cur_quadg.levels)][0].flags & GMAP_FULL)
- /* <<Netsukuku is completely full, sry>> */
- err_reply = E_NTK_FULL;
- else
- /* Our Quadro Group is full, bye */
- err_reply = E_QGROUP_FULL;
-
- pkt_fill_hdr(&pkt.hdr, HOOK_PKT, rq_pkt.hdr.id, PUT_FREE_NODES, 0);
- err = pkt_err(pkt, err_reply, 1);
- goto finish;
- }
-
- /* Ok, we've found one, so let's roll the pkt */
- setzero(&fn_pkt, sizeof(fn_pkt));
-
- /*
- * Fill the reply packet
- */
- fn_pkt.fn_hdr.max_levels = me.cur_quadg.levels;
- inet_copy_ipdata(fn_pkt.fn_hdr.ipstart, &me.cur_quadg.ipstart[level]);
- fn_pkt.fn_hdr.level = level;
- fn_pkt.fn_hdr.gid = me.cur_quadg.gid[level];
-
- /*
- * Update the hook_join_rate and stores give the stores in
- * `fn_pkt.fn_hdr.join_rate' the join_rate destined to `rq_pkt.from'
- */
- links = me.cur_node->links - rnodes_rehooked - 1;
- if (hook_join_rate >= links && links > 0)
- fn_pkt.fn_hdr.join_rate = hook_join_rate / links;
- else if (hook_join_rate > 0)
- fn_pkt.fn_hdr.join_rate = 1;
- else
- fn_pkt.fn_hdr.join_rate = 0;
- hook_join_rate -= fn_pkt.fn_hdr.join_rate;
- hook_join_rate = hook_join_rate < 0 ? 0 : hook_join_rate;
- rnodes_rehooked++;
-
- /*
- * Creates the list of the free nodes, which belongs to the gnode. If
- * the gnode level is 1 it scans the int_map to find all the MAP_VOID
- * nodes, otherwise it scans the gnode map at level-1 searching for
- * GMAP_VOID gnodes.
- */
- e = 0;
- if (level == 1) {
- for (i = 0; i < MAXGROUPNODE; i++)
- if (me.int_map[i].flags & MAP_VOID) {
- SET_BIT(fn_pkt.free_nodes, i);
- e++;
- }
- } else {
- for (i = 0; i < MAXGROUPNODE; i++)
- if (me.ext_map[_EL(level - 1)][i].flags & GMAP_VOID ||
- me.ext_map[_EL(level - 1)][i].g.flags & MAP_VOID) {
- SET_BIT(fn_pkt.free_nodes, i);
- e++;
- }
- }
- fn_pkt.fn_hdr.nodes = (u_char) e - 1;
-
- /* Go pkt, go! Follow your instinct */
- pkt_sz = FREE_NODES_SZ((fn_pkt.fn_hdr.nodes + 1));
- pkt_fill_hdr(&pkt.hdr, HOOK_PKT, rq_pkt.hdr.id, PUT_FREE_NODES,
- pkt_sz);
- pkt.msg = xzalloc(pkt_sz);
-
- p = pkt.msg;
- memcpy(p, &fn_pkt, sizeof(fn_pkt));
- ints_host_to_network(p, free_nodes_hdr_iinfo);
-
- debug(DBG_INSANE, "Reply %s to %s", re_to_str(pkt.hdr.op), ntop);
- err = pkt_send(&pkt);
-
- finish:
- if (err < 0) {
- error
- ("put_free_nodes(): Cannot send the PUT_FREE_NODES reply to %s.",
- ntop);
- ret = -1;
- }
- pkt_free(&pkt, 0);
- return ret;
- }
-
-
- /*\
- * * * put/get qspn_round * *
- \*/
-
- /*
- * get_qspn_round: It send the GET_QSPN_ROUND request, used to retrieve the
- * qspn ids and and qspn times. (see hook.h).
- */
- int
- get_qspn_round(map_node * dst_rnode, struct timeval to_rtt,
- struct timeval *qtime, int *qspn_id, int *qspn_gcount)
- {
- PACKET pkt, rpkt;
- struct timeval cur_t;
- ssize_t err;
- int ret = 0, level;
- char *buf = 0;
- u_char max_levels;
- int_info qr_pkt_iinfo;
-
- setzero(&pkt, sizeof(PACKET));
- setzero(&rpkt, sizeof(PACKET));
-
- hook_fill_rq(dst_rnode, &pkt, GET_QSPN_ROUND) < 0 && _return(-1);
- pkt_addtimeout(&pkt, HOOK_RQ_TIMEOUT, 1, 0);
-
- err =
- rnl_send_rq(dst_rnode, &pkt, 0, GET_QSPN_ROUND, 0, PUT_QSPN_ROUND,
- 1, &rpkt);
- if (err < 0)
- ERROR_FINISH(ret, -1, finish);
-
- buf = rpkt.msg;
- bufget(&max_levels, sizeof(u_char));
- if (QSPN_ROUND_PKT_SZ(max_levels) != rpkt.hdr.sz ||
- max_levels > FAMILY_LVLS) {
- error("Malformed PUT_QSPN_ROUND request hdr from %s",
- inet_to_str(pkt.to));
- ERROR_FINISH(ret, -1, finish);
- }
-
- /* Convert the pkt from network to host order */
- int_info_copy(&qr_pkt_iinfo, &qspn_round_pkt_iinfo);
- qr_pkt_iinfo.int_offset[1] =
- me.cur_quadg.levels * sizeof(int) + sizeof(char);
- qr_pkt_iinfo.int_offset[2] =
- qr_pkt_iinfo.int_offset[1] + sizeof(struct timeval) * max_levels;
- qr_pkt_iinfo.int_nmemb[0] = max_levels;
- qr_pkt_iinfo.int_nmemb[1] = max_levels * 2;
- ints_network_to_host(rpkt.msg, qr_pkt_iinfo);
-
- /* Restoring the qspn_id and the qspn_round time */
- bufget(qspn_id, max_levels * sizeof(int));
- bufget(qtime, max_levels * sizeof(struct timeval));
-
- gettimeofday(&cur_t, 0);
- for (level = 0; level < max_levels; level++) {
- timeradd(&to_rtt, &qtime[level], &qtime[level]);
- timersub(&cur_t, &qtime[level], &qtime[level]);
- }
-
- /* Extracting the qspn_gnode_count */
- bufget(qspn_gcount, sizeof(u_int) * GCOUNT_LEVELS);
-
- finish:
- pkt_free(&pkt, 0);
- pkt_free(&rpkt, 0);
- return ret;
- }
-
- /*
- * put_qspn_round
- *
- * It sends the current qspn times and ids to rq_pkt.from.
- */
- int
- put_qspn_round(PACKET rq_pkt)
- {
- /*
- * We cannot use this elegant struct because gcc is bugged, -_.
- * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27945
- *
- * We have to wait some years, then when gcc4 will be obsolete (and
- * the bug will be solved), we'll activate it.
- *
- * struct qspn_round_pkt {
- * u_char max_levels;
- * int32_t qspn_id[me.cur_quadg.levels];
- * struct timeval _PACKED_ qtime[me.cur_quadg.levels];
- * u_int gcount[GCOUNT_LEVELS];
- * }_PACKED_ qr_pkt;
- */
- char qr_pkt[QSPN_ROUND_PKT_SZ(me.cur_quadg.levels)];
- int_info qr_pkt_iinfo;
-
- PACKET pkt;
- struct timeval cur_t, *tptr;
- int ret = 0;
- ssize_t err, pkt_sz;
- u_char level;
- const char *ntop;
- u_char max_levels;
- char *buf = 0;
-
- ntop = inet_to_str(rq_pkt.from);
-
- setzero(&pkt, sizeof(PACKET));
- pkt_addto(&pkt, &rq_pkt.from);
- pkt_addport(&pkt, ntk_tcp_port);
- pkt_addsk(&pkt, my_family, rq_pkt.sk, rq_pkt.sk_type);
- pkt_add_dev(&pkt, rq_pkt.dev, 1);
- pkt_addcompress(&pkt);
-
- /* We fill the qspn_id and the qspn round time */
- buf = qr_pkt;
- max_levels = me.cur_quadg.levels;
- bufput(&max_levels, sizeof(u_char));
- bufput(me.cur_qspn_id, sizeof(int) * max_levels);
-
- gettimeofday(&cur_t, 0);
- for (level = 0; level < max_levels; level++) {
- update_qspn_time(level, 0);
- tptr = (struct timeval *) buf;
- timersub(&cur_t, &me.cur_qspn_time[level], tptr);
- buf += sizeof(struct timeval);
- }
-
- /* copy in the pkt the qspn_gnode_count */
- bufput(qspn_gnode_count, sizeof(qspn_gnode_count));
-
- /* Convert the pkt from host to network order */
- int_info_copy(&qr_pkt_iinfo, &qspn_round_pkt_iinfo);
- qr_pkt_iinfo.int_offset[1] =
- me.cur_quadg.levels * sizeof(int) + sizeof(char);
- qr_pkt_iinfo.int_offset[2] =
- qr_pkt_iinfo.int_offset[1] + sizeof(struct timeval) * max_levels;
- qr_pkt_iinfo.int_nmemb[0] = me.cur_quadg.levels;
- qr_pkt_iinfo.int_nmemb[1] = me.cur_quadg.levels * 2;
- ints_host_to_network(qr_pkt, qr_pkt_iinfo);
-
- /* fill the pkt header */
- pkt_sz = sizeof(qr_pkt);
- pkt_fill_hdr(&pkt.hdr, HOOK_PKT, rq_pkt.hdr.id, PUT_QSPN_ROUND,
- pkt_sz);
- pkt.msg = xzalloc(pkt_sz);
-
- /* Go pkt, go! Follow your instinct */
- debug(DBG_INSANE, "Reply %s to %s", re_to_str(pkt.hdr.op), ntop);
- memcpy(pkt.msg, &qr_pkt, sizeof(qr_pkt));
- err = pkt_send(&pkt);
-
- if (err < 0) {
- error
- ("put_qspn_round(): Cannot send the PUT_QSPN_ROUND reply to %s.",
- ntop);
- ret = -1;
- }
- pkt_free(&pkt, 0);
- return ret;
- }
-
-
- /*\
- * * * put/get ext_map * *
- \*/
-
- int
- put_ext_map(PACKET rq_pkt)
- {
- PACKET pkt;
- const char *ntop;
- int ret = 0;
- ssize_t err;
- size_t pkt_sz = 0;
-
- ntop = inet_to_str(rq_pkt.from);
-
- setzero(&pkt, sizeof(PACKET));
- pkt_addsk(&pkt, my_family, rq_pkt.sk, rq_pkt.sk_type);
- pkt_addcompress(&pkt);
-
- pkt.msg =
- pack_extmap(me.ext_map, MAXGROUPNODE, &me.cur_quadg, &pkt_sz);
- pkt.hdr.sz = pkt_sz;
- debug(DBG_INSANE, "Reply %s to %s", re_to_str(PUT_EXT_MAP), ntop);
- err = send_rq(&pkt, 0, PUT_EXT_MAP, rq_pkt.hdr.id, 0, 0, 0);
- if (err < 0) {
- error("put_ext_maps(): Cannot send the PUT_EXT_MAP reply to %s.",
- ntop);
- ERROR_FINISH(ret, -1, finish);
- }
-
- finish:
- pkt_free(&pkt, 0);
- return ret;
- }
-
- /*
- * get_ext_map: It sends the GET_EXT_MAP request to retrieve the
- * dst_node's ext_map.
- */
- map_gnode **
- get_ext_map(map_node * dst_rnode, quadro_group * new_quadg)
- {
- PACKET pkt, rpkt;
- char *pack;
- int err;
- map_gnode **ext_map = 0, **ret = 0;
-
- setzero(&pkt, sizeof(PACKET));
- setzero(&rpkt, sizeof(PACKET));
-
- hook_fill_rq(dst_rnode, &pkt, GET_EXT_MAP) < 0 && _return(0);
- pkt_addtimeout(&pkt, HOOK_RQ_TIMEOUT, 1, 0);
-
- err = rnl_send_rq(dst_rnode, &pkt, 0, GET_EXT_MAP, 0, PUT_EXT_MAP, 1,
- &rpkt);
- if (err < 0) {
- ret = 0;
- goto finish;
- }
-
- pack = rpkt.msg;
- ret = ext_map = unpack_extmap(pack, new_quadg);
- if (!ext_map)
- error
- ("get_ext_map: Malformed ext_map. Cannot unpack the ext_map.");
- finish:
- pkt_free(&pkt, 0);
- pkt_free(&rpkt, 0);
- return ret;
- }
-
- /*\
- * * * put/get int_map * *
- \*/
-
- int
- put_int_map(PACKET rq_pkt)
- {
- PACKET pkt;
- map_node *map = me.int_map;
- const char *ntop;
- int ret = 0;
- ssize_t err;
- size_t pkt_sz = 0;
-
- ntop = inet_to_str(rq_pkt.from);
-
- setzero(&pkt, sizeof(PACKET));
- pkt_addto(&pkt, &rq_pkt.from);
- pkt_addsk(&pkt, my_family, rq_pkt.sk, rq_pkt.sk_type);
- pkt_add_dev(&pkt, rq_pkt.dev, 1);
- pkt_addcompress(&pkt);
-
- pkt.msg = pack_map(map, 0, MAXGROUPNODE, me.cur_node, &pkt_sz);
- pkt.hdr.sz = pkt_sz;
- debug(DBG_INSANE, "Reply %s to %s", re_to_str(PUT_INT_MAP), ntop);
- err = send_rq(&pkt, 0, PUT_INT_MAP, rq_pkt.hdr.id, 0, 0, 0);
- if (err < 0) {
- error("put_int_map(): Cannot send the PUT_INT_MAP reply to %s.",
- ntop);
- ERROR_FINISH(ret, -1, finish);
- }
- finish:
- pkt_free(&pkt, 0);
- return ret;
- }
-
- /*
- * get_int_map: It sends the GET_INT_MAP request to retrieve the
- * dst_node's int_map.
- */
- map_node *
- get_int_map(map_node * dst_rnode, map_node ** new_root)
- {
- PACKET pkt, rpkt;
- map_node *int_map, *ret = 0;
- int err;
- char *pack;
-
- setzero(&pkt, sizeof(PACKET));
- setzero(&rpkt, sizeof(PACKET));
-
- hook_fill_rq(dst_rnode, &pkt, GET_INT_MAP) < 0 && _return(0);
- pkt_addtimeout(&pkt, HOOK_RQ_TIMEOUT, 1, 0);
-
- err = rnl_send_rq(dst_rnode, &pkt, 0, GET_INT_MAP, 0, PUT_INT_MAP, 1,
- &rpkt);
- if (err < 0) {
- ret = 0;
- goto finish;
- }
-
- pack = rpkt.msg;
- ret = int_map = unpack_map(pack, 0, new_root, MAXGROUPNODE,
- MAXRNODEBLOCK_PACK_SZ);
- if (!int_map)
- error("get_int_map(): Malformed int_map. Cannot load it");
-
- /*Finished, yeah */
- finish:
- pkt_free(&pkt, 0);
- pkt_free(&rpkt, 0);
- return ret;
- }
-
- /*\
- * * * put/get bnode_map * *
- \*/
-
- int
- put_bnode_map(PACKET rq_pkt)
- {
- PACKET pkt;
- map_bnode **bmaps = me.bnode_map;
- const char *ntop;
- int ret = 0;
- ssize_t err;
- size_t pack_sz = 0;
-
- ntop = inet_to_str(rq_pkt.from);
-
- setzero(&pkt, sizeof(PACKET));
- pkt_addto(&pkt, &rq_pkt.from);
- pkt_addsk(&pkt, my_family, rq_pkt.sk, rq_pkt.sk_type);
- pkt_add_dev(&pkt, rq_pkt.dev, 1);
- pkt_addcompress(&pkt);
-
- pkt.msg =
- pack_all_bmaps(bmaps, me.bmap_nodes, me.ext_map, me.cur_quadg,
- &pack_sz);
- pkt.hdr.sz = pack_sz;
-
- debug(DBG_INSANE, "Reply %s to %s", re_to_str(PUT_BNODE_MAP), ntop);
- err = send_rq(&pkt, 0, PUT_BNODE_MAP, rq_pkt.hdr.id, 0, 0, 0);
- if (err < 0) {
- error
- ("put_bnode_maps(): Cannot send the PUT_BNODE_MAP reply to %s.",
- ntop);
- ERROR_FINISH(ret, -1, finish);
- }
-
- finish:
- pkt_free(&pkt, 0);
- return ret;
- }
-
- /*
- * get_bnode_map: It sends the GET_BNODE_MAP request to retrieve the
- * dst_node's bnode_map.
- */
- map_bnode **
- get_bnode_map(map_node * dst_rnode, u_int ** bmap_nodes)
- {
- PACKET pkt, rpkt;
- int err;
- map_bnode **bnode_map, **ret = 0;
- char *pack;
-
- setzero(&pkt, sizeof(PACKET));
- setzero(&rpkt, sizeof(PACKET));
-
- hook_fill_rq(dst_rnode, &pkt, GET_BNODE_MAP) < 0 && _return(0);
- pkt_addtimeout(&pkt, HOOK_RQ_TIMEOUT, 1, 0);
-
- err = rnl_send_rq(dst_rnode, &pkt, 0, GET_BNODE_MAP, 0, PUT_BNODE_MAP,
- 1, &rpkt);
- if (err < 0) {
- ret = 0;
- goto finish;
- }
-
- /* Extracting the map... */
- pack = rpkt.msg;
- ret = bnode_map =
- unpack_all_bmaps(pack, FAMILY_LVLS, me.ext_map, bmap_nodes,
- MAXGROUPNODE, MAXBNODE_RNODEBLOCK);
- if (!bnode_map)
- error("get_bnode_map(): Malformed bnode_map. Cannot load it");
-
- finish:
- pkt_free(&pkt, 0);
- pkt_free(&rpkt, 0);
- return ret;
- }
-
-
- /*\
- * * * put/get internet gateways list * *
- \*/
-
- int
- put_internet_gws(PACKET rq_pkt)
- {
- PACKET pkt;
- const char *ntop;
- int ret = 0;
- ssize_t err;
- size_t pack_sz = 0;
-
- ntop = inet_to_str(rq_pkt.from);
-
- setzero(&pkt, sizeof(PACKET));
- pkt_addto(&pkt, &rq_pkt.from);
- pkt_addsk(&pkt, my_family, rq_pkt.sk, rq_pkt.sk_type);
- pkt_add_dev(&pkt, rq_pkt.dev, 1);
- pkt_addcompress(&pkt);
-
- pkt.msg = pack_igws(me.igws, me.igws_counter, me.cur_quadg.levels,
- (int *) &pack_sz);
- pkt.hdr.sz = pack_sz;
-
- debug(DBG_INSANE, "Reply %s to %s", re_to_str(PUT_INTERNET_GWS), ntop);
- err = send_rq(&pkt, 0, PUT_INTERNET_GWS, rq_pkt.hdr.id, 0, 0, 0);
- if (err < 0) {
- error("put_internet_gws(): Cannot send the PUT_INTERNET_GWS "
- "reply to %s.", ntop);
- ERROR_FINISH(ret, -1, finish);
- }
-
- finish:
- pkt_free(&pkt, 0);
- return ret;
- }
-
- /*
- * get_internet_gws: It sends the GET_INTERNET_GWS request to retrieve the
- * Internet Gateways list from `to'.
- */
- inet_gw **
- get_internet_gws(map_node * dst_rnode, int **igws_counter)
- {
- PACKET pkt, rpkt;
- int err, ret = 0;
- inet_gw **igws = 0;
- char *pack;
-
- setzero(&pkt, sizeof(PACKET));
- setzero(&rpkt, sizeof(PACKET));
-
- hook_fill_rq(dst_rnode, &pkt, GET_INTERNET_GWS) < 0 && _return(0);
- pkt_addtimeout(&pkt, HOOK_RQ_TIMEOUT, 1, 0);
-
- err = rnl_send_rq(dst_rnode, &pkt, 0, GET_INTERNET_GWS, 0,
- PUT_INTERNET_GWS, 1, &rpkt);
- if (err < 0)
- ERROR_FINISH(ret, 0, finish);
-
- /* Extracting the list... */
- pack = rpkt.msg;
- ret =
- unpack_igws(pack, rpkt.hdr.sz, me.int_map, me.ext_map, FAMILY_LVLS,
- &igws, igws_counter);
- if (ret < 0) {
- error
- ("get_internet_gws(): Malformed internet_gws. Cannot load it");
- igws = 0;
- }
-
- finish:
- pkt_free(&pkt, 0);
- pkt_free(&rpkt, 0);
- return igws;
- }
-
-
- /*
- * hook_set_all_ips
- *
- * Sets the same `ip' to all the devices.
- */
- void
- hook_set_all_ips(inet_prefix ip, interface * ifs, int ifs_n)
- {
- const char *ntop;
- ntop = inet_to_str(ip);
-
- loginfo("Setting the %s ip to all the interfaces", ntop);
-
- if (my_family == AF_INET) {
- /* Down & Up: reset the configurations of all the interfaces */
- set_all_ifs(ifs, ifs_n, set_dev_down);
- set_all_ifs(ifs, ifs_n, set_dev_up);
- } else {
- ip_addr_flush_all_ifs(ifs, ifs_n, my_family, RT_SCOPE_UNIVERSE);
- ip_addr_flush_all_ifs(ifs, ifs_n, my_family, RT_SCOPE_SITE);
- }
-
- if (set_all_dev_ip(ip, ifs, ifs_n) < 0)
- fatal("Cannot set the %s ip to all the interfaces", ntop);
- if (restricted_mode && (server_opt.use_shared_inet ||
- server_opt.share_internet)) {
- set_dev_down(DEFAULT_TUNL_IF);
- set_dev_up(DEFAULT_TUNL_IF);
- if (set_dev_ip(ip, DEFAULT_TUNL_IF) < 0)
- fatal("Cannot assign an IP to the default tunnel");
- }
- }
-
- /*
- * create_gnodes
- *
- * This function is used to create a new gnode (or more) when we are the first
- * node in the area or when all the other gnodes are full.
- * Our ip will be set to `ip'. If `ip' is NULL, a random ip is chosen.
- * create_gnodes() sets also all the vital variables for the new gnode/gnodes
- * like me.cur_quadg, me.cur_ip, etc...
- * `final_level' is the highest level where we create the gnode, all the other
- * gnodes we create are in the sub-levels of `final_level'.
- */
- int
- create_gnodes(inet_prefix * ip, int final_level)
- {
- int i;
-
- if (!ip) {
- random_ip(0, 0, 0, FAMILY_LVLS, me.ext_map, 0, &me.cur_ip,
- my_family);
- } else
- inet_copy(&me.cur_ip, ip);
-
- if (restricted_mode)
- inet_setip_localaddr(&me.cur_ip, my_family, restricted_class);
-
- if (!final_level)
- final_level = FAMILY_LVLS;
-
- /*
- * We remove all the traces of the old gnodes in the ext_map to add the
- * new ones.
- */
- if (!(me.cur_node->flags & MAP_HNODE))
- for (i = 1; i < final_level; i++) {
- me.cur_quadg.gnode[_EL(i)]->flags &= ~GMAP_ME;
- me.cur_quadg.gnode[_EL(i)]->g.flags &= ~MAP_ME & ~MAP_GNODE;
- }
-
- /* Now, we update the ext_map with the new gnodes */
- me.cur_quadg.levels = FAMILY_LVLS;
- reset_extmap(me.ext_map, me.cur_quadg.levels, 0);
- iptoquadg(me.cur_ip, me.ext_map, &me.cur_quadg,
- QUADG_GID | QUADG_GNODE | QUADG_IPSTART);
-
- /* Set the new flags */
- for (i = 1; i < final_level; i++) {
- me.cur_quadg.gnode[_EL(i)]->flags &= ~GMAP_VOID;
- me.cur_quadg.gnode[_EL(i)]->flags |= GMAP_ME;
- me.cur_quadg.gnode[_EL(i)]->g.flags &= ~MAP_VOID;
- me.cur_quadg.gnode[_EL(i)]->g.flags |= MAP_ME | MAP_GNODE;
-
- /* Increment the gnode seeds counter */
- gnode_inc_seeds(&me.cur_quadg, i);
- }
-
- /* Reset the `qspn_gnode_count' counter */
- qspn_reset_gcount(qspn_gnode_count, final_level, 1);
-
- /* Tidying up the internal map */
- if (free_the_tmp_cur_node) {
- xfree(me.cur_node);
- free_the_tmp_cur_node = 0;
- }
- reset_int_map(me.int_map, 0);
- me.cur_node = &me.int_map[me.cur_quadg.gid[0]];
- me.cur_node->flags &= ~MAP_VOID;
- me.cur_node->flags |= MAP_ME;
-
- return 0;
- }
-
- /*
- * create_new_qgroup
- *
- * this is just a wrapper to create_gnodes(). It creates completely
- * random gnodes in all the levels.
- */
- void
- create_new_qgroup(int hook_level)
- {
- const char *ntop;
-
- if (we_are_rehooking)
- create_gnodes(&rk_gnode_ip, hook_level + 1);
- else
- create_gnodes(0, FAMILY_LVLS);
- ntop = inet_to_str(me.cur_ip);
-
- hook_set_all_ips(me.cur_ip, me.cur_ifs, me.cur_ifs_n);
-
- loginfo("Now we are in a brand new gnode. The ip %s is now"
- " used.", ntop);
- }
-
- /*
- * update_join_rate
- *
- * it updates the `hook_join_rate' according to `gnode_count', which has the
- * gnode count of `hook_gnode' and to `fn_hdr', which is the free_nodes_hdr
- * received from `hook_gnode'.
- * `old_gcount' is the gnode_count we had before the start of the rehook.
- * If a new_gnode has to be created 1 is returned, (and hook_join_rate will be
- * 0), otherwise 0 is the returned value.
- * If we aren't rehooking or if it isn't necessary to consider the join_rate,
- * -1 is returned.
- */
- int
- update_join_rate(map_gnode * hook_gnode, int hook_level,
- u_int * old_gcount, u_int * gnode_count,
- struct free_nodes_hdr *fn_hdr)
- {
- u_int free_nodes, total_bnodes;
- int new_gnode = 0, i;
-
- if (!hook_level || !hook_gnode || !we_are_rehooking)
- return -1;
-
- /*
- * `free_nodes' is the number of VOID nodes present at the
- * `hook_level' in `hook_gnode', and it is the difference
- * between the maximum number of nodes in that level and the
- * actual number of nodes in it (gnode_count).
- */
- free_nodes =
- NODES_PER_LEVEL(hook_level) - gnode_count[_EL(hook_level)];
-
- if (old_gcount[_EL(hook_level)] <= free_nodes)
- return -1;
-
- debug(DBG_SOFT,
- "update_join_rate: free_nodes %d, fn_hdr->join_rate %d",
- free_nodes, fn_hdr->join_rate);
-
- /* There aren't free nodes in `hook_gnode', so skip this function */
- if (free_nodes <= 0) {
- new_gnode = 1;
- goto finish;
- }
-
- if (map_find_bnode_rnode
- (me.bnode_map[hook_level - 1], me.bmap_nodes[hook_level - 1],
- hook_gnode) >= 0) {
- /* We border on `hook_gnode' so we initialize
- * `hook_join_rate' for this new re-hook session,
- * later we'll hook at `hook_gnode'. */
-
- hook_join_rate = free_nodes;
-
- for (i = hook_level - 1; i >= 0; i--) {
-
- /* `total_bnodes' = how many bnodes border to
- * `hook_gnode' in level `i'th */
- total_bnodes =
- map_count_bnode_rnode(me.bnode_map[i], me.bmap_nodes[i],
- hook_gnode);
-
- total_bnodes = total_bnodes ? total_bnodes : 1;
- hook_join_rate /= total_bnodes;
- }
- new_gnode = 0;
- } else if (fn_hdr->join_rate) {
- /* The join_rate we got from our rnode is > 0, so
- * we hook at `hook_gnode'. */
- hook_join_rate = fn_hdr->join_rate;
- new_gnode = 0;
- } else
- new_gnode = 1;
-
- if (!new_gnode) {
- /* Don't count us in the join_rate, 'cause we are rehooking */
- hook_join_rate--;
- hook_join_rate = hook_join_rate < 0 ? 0 : hook_join_rate;
- }
-
-
- debug(DBG_NOISE, "update_join_rate: new join_rate %u, new_gnode %d",
- hook_join_rate, new_gnode);
-
- finish:
- return new_gnode;
- }
-
- /*
- * hook_init
- *
- * inits the hook.c code. Call this function only once, at the start of the
- * daemon.
- */
- int
- hook_init(void)
- {
- /* register the hook's ops in the pkt_op_table */
- add_pkt_op(GET_FREE_NODES, SKT_TCP, ntk_tcp_port, put_free_nodes);
- add_pkt_op(PUT_FREE_NODES, SKT_TCP, ntk_tcp_port, 0);
- add_pkt_op(GET_QSPN_ROUND, SKT_TCP, ntk_tcp_port, put_qspn_round);
- add_pkt_op(PUT_QSPN_ROUND, SKT_TCP, ntk_tcp_port, 0);
- add_pkt_op(GET_INT_MAP, SKT_TCP, ntk_tcp_port, put_int_map);
- add_pkt_op(PUT_INT_MAP, SKT_TCP, ntk_tcp_port, 0);
- add_pkt_op(GET_EXT_MAP, SKT_TCP, ntk_tcp_port, put_ext_map);
- add_pkt_op(PUT_EXT_MAP, SKT_TCP, ntk_tcp_port, 0);
- add_pkt_op(GET_BNODE_MAP, SKT_TCP, ntk_tcp_port, put_bnode_map);
- add_pkt_op(PUT_BNODE_MAP, SKT_TCP, ntk_tcp_port, 0);
- add_pkt_op(GET_INTERNET_GWS, SKT_TCP, ntk_tcp_port, put_internet_gws);
- add_pkt_op(PUT_INTERNET_GWS, SKT_TCP, ntk_tcp_port, 0);
-
- total_hooks = 0;
- we_are_rehooking = 0;
- free_the_tmp_cur_node = 0;
-
- hook_reset();
-
- debug(DBG_NORMAL, "Activating ip_forward and disabling rp_filter");
- route_ip_forward(my_family, 1);
- route_rp_filter_all_dev(my_family, me.cur_ifs, me.cur_ifs_n, 0);
- if (restricted_mode && (server_opt.share_internet ||
- server_opt.share_internet))
- route_rp_filter(my_family, DEFAULT_TUNL_IF, 0);
-
-
- return 0;
- }
-
- /*
- * hook_reset: resets all the variables needed to hook. This function is
- * called at the beginning of netsukuku_hook().
- */
- void
- hook_reset(void)
- {
- u_int idata[MAX_IP_INT];
-
- /* We use a fake root_node for a while */
- if (free_the_tmp_cur_node)
- xfree(me.cur_node);
- free_the_tmp_cur_node = 1;
- me.cur_node = xzalloc(sizeof(map_node));
- me.cur_node->flags |= MAP_HNODE;
-
- rnodes_rehooked = hook_join_rate = 0;
-
- /*
- * Do not reply to any request while we are hooking, except the radar
- * ECHO_ME, ECHO_REPLY, and all the replies.
- */
- op_filter_reset(OP_FILTER_DROP);
- op_filter_reset_re(OP_FILTER_ALLOW);
- op_filter_clr(ECHO_ME);
- op_filter_clr(ECHO_REPLY);
-
- /*
- * We set the dev ip to HOOKING_IP+random_number to begin our
- * transaction.
- */
- setzero(idata, MAX_IP_SZ);
- if (my_family == AF_INET) {
- idata[0] =
- restricted_class ==
- RESTRICTED_10 ? HOOKING_IP_10 : HOOKING_IP_172;
- } else
- idata[0] = HOOKING_IPV6;
-
- if (my_family == AF_INET6)
- idata[0] += rand_range(0, MAXGROUPNODE - 2);
- else
- idata[0] += rand_range(0, MAXGROUPNODE - 2);
-
- inet_setip_raw(&me.cur_ip, idata, my_family);
- iptoquadg(me.cur_ip, me.ext_map, &me.cur_quadg,
- QUADG_GID | QUADG_GNODE | QUADG_IPSTART);
-
- hook_set_all_ips(me.cur_ip, me.cur_ifs, me.cur_ifs_n);
- }
-
-
- /*
- * hook_first_radar_scan: launches the first scan to know what rnodes we have
- * around us.
- * If a new gnode has to be created, 1 is returned.
- */
- int
- hook_first_radar_scan(map_gnode * hook_gnode, int hook_level,
- quadro_group * old_quadg)
- {
- int total_hooking_nodes, i;
-
- /*
- * If we are rehooking to `hook_gnode' tell the radar to ignore all
- * the other rnodes, which don't belong to it.
- */
- if (hook_gnode && we_are_rehooking) {
- int gid[NMEMB(old_quadg->gid)];
-
- memcpy(gid, old_quadg->gid, sizeof(old_quadg->gid));
- gid[hook_level] =
- pos_from_gnode(hook_gnode, me.ext_map[_EL(hook_level)]);
- new_rnode_allowed(&alwd_rnodes, &alwd_rnodes_counter, gid,
- hook_level, FAMILY_LVLS);
- }
-
- /*
- * If we are in restricted mode, ignore the restricted nodes which
- * belong to our opposite restricted class. So, if we are 10.0.0.1
- * ignore 172.x.x.x, and viceversa. This happens only in ipv4.
- */
- if (restricted_mode && my_family == AF_INET) {
- int gid[IPV4_LEVELS] = { 0, 0, 0, 0 };
-
- if (restricted_class == RESTRICTED_10)
- gid[3] = 10;
- else
- gid[3] = 172;
- new_rnode_allowed(&alwd_rnodes, &alwd_rnodes_counter,
- gid, 3, FAMILY_LVLS);
- }
-
- /*
- * We do our first scans to know what we've around us. The rnodes are
- * kept in me.cur_node->r_nodes.
- * The fastest one is in me.cur_node->r_nodes[0].
- *
- * If after MAX_FIRST_RADAR_SCANS# tries we haven't found any rnodes
- * we start as a new gnode.
- */
-
- for (i = 0; i < MAX_FIRST_RADAR_SCANS; i++) {
- me.cur_node->flags |= MAP_HNODE;
-
- loginfo("Launching radar_scan %d of %d", i + 1,
- MAX_FIRST_RADAR_SCANS);
-
- if (radar_scan(0))
- fatal("%s:%d: Scan of the area failed. Cannot continue.",
- ERROR_POS);
- total_hooking_nodes = count_hooking_nodes();
-
- if (!me.cur_node->links ||
- (me.cur_node->links == total_hooking_nodes && !hook_retry)) {
- /*
- * If we have 0 nodes around us, we are alone, so we create a
- * new gnode.
- * If all the nodes around us are hooking and we started hooking
- * before them, we create the new gnode.
- */
- if (!me.cur_node->links) {
- /*
- * We haven't found any rnodes. Let's retry the
- * radar_scan if i+1<MAX_FIRST_RADAR_SCANS
- */
- if (i + 1 < MAX_FIRST_RADAR_SCANS)
- goto hook_retry_scan;
-
- loginfo("No nodes found! This is a black zone. "
- "Creating a new_gnode.");
- } else
- loginfo("There are %d nodes around, which are hooking"
- " like us, but we came first so we have "
- "to create the new gnode", total_hooking_nodes);
- create_new_qgroup(hook_level);
-
- return 1;
- } else if (hook_retry) {
- /*
- * There are only hooking nodes, but we started the hooking
- * after them, so we wait until some of them create the new
- * gnode.
- */
- loginfo
- ("I've seen %d hooking nodes around us, and one of them "
- "is becoming a new gnode.\n"
- " We wait, then we'll restart the hook.",
- total_hooking_nodes);
-
- usleep(rand_range(0, 1024)); /* ++entropy, thx to katolaz :) */
- sleep(MAX_RADAR_WAIT);
- i--;
- } else
- break;
-
- hook_retry_scan:
- reset_radar();
- rnode_destroy(me.cur_node);
- setzero(me.cur_node, sizeof(map_node));
- me.cur_node->flags |= MAP_HNODE;
- qspn_b_del_all_dead_rnodes();
- }
- if (me.cur_node->links < 1) {
- loginfo("We have %d nodes around us. (%d are hooking)",
- me.cur_node->links, total_hooking_nodes);
- } else if (me.cur_node->links == 1) {
- loginfo("We have %d node around us. (%d are hooking)",
- me.cur_node->links, total_hooking_nodes);
- }
- return 0;
- }
-
-
- /*
- * hook_get_free_nodes
- *
- * gets the free_nodes list and the qson_round info from our nearest rnode.
- * In `fn_hdr', `fnodes', `gnode_ipstart' and `new_gcount' there will be stored the relative
- * value.
- * If a new gnode has to be created 1 is returned.
- */
- int
- hook_get_free_nodes(int hook_level, struct free_nodes_hdr *fn_hdr,
- u_char * fnodes, inet_prefix * gnode_ipstart,
- u_int * new_gcount, struct rnode_list **ret_rnl)
- {
- struct radar_queue *rq = 0;
- struct rnode_list *rnl = rlist;
- int e = 0, err;
-
- /*
- * Now we choose the nearest rnode we found and we send it the
- * GET_FREE_NODES request.
- */
- list_for(rnl) {
- if (rnl->node->flags & MAP_HNODE)
- continue;
-
- err = get_free_nodes(rnl->node, fn_hdr, fnodes);
- if (err == -2)
- fatal("Netsukuku is full! Bring down some nodes and retry");
- else if (err == -1)
- continue;
-
- /* Extract the ipstart of the gnode */
- inet_setip(gnode_ipstart, (u_int *) fn_hdr->ipstart, my_family);
-
- /* Get the qspn round info */
- rq = find_node_radar_q(rnl->node);
- if (!get_qspn_round(rnl->node, rq->final_rtt, me.cur_qspn_time,
- me.cur_qspn_id, (int *) new_gcount)) {
- e = 1;
- break;
- }
- }
-
- *ret_rnl = rnl;
-
- if (!e) {
- loginfo("It seems all the quadro_groups in this area are full "
- "or are not cooperating.\n "
- "We are going to create a new gnode");
-
- create_new_qgroup(hook_level);
- return 1;
- }
-
- return 0;
- }
-
- /*
- * hook_choose_new_ip
- *
- * after reading the received `fn_hdr', it decides our new IP and if we have to
- * create a new gnode it returns 1.
- */
- int
- hook_choose_new_ip(map_gnode * hook_gnode, int hook_level,
- struct free_nodes_hdr *fn_hdr, u_char * fnodes,
- inet_prefix * gnode_ipstart)
- {
- int new_gnode, e;
-
- /*
- * Let's see if we can re-hook at `hook_gnode' or if we have
- * to create a new gnode, in other words: update the join_rate.
- */
- new_gnode = update_join_rate(hook_gnode, hook_level, qspn_old_gcount,
- qspn_gnode_count, fn_hdr);
- if (new_gnode > 0) {
- /*
- * The `hook_gnode' gnode cannot take all the nodes of our
- * gnode so we just give up and create a new gnode, which has
- * a gid based on the hash of our current gid.
- */
- inet_copy(&me.cur_ip, &rk_gnode_ip);
- debug(DBG_NORMAL, "rehook_create_gnode: %s is our new ip",
- inet_to_str(me.cur_ip));
- } else {
- /*
- * We are hooking fine,
- * let's choose a random ip using the free nodes list we received.
- */
-
- e = rand_range(0, fn_hdr->nodes - 1);
- if (fn_hdr->level == 1) {
- new_gnode = 0;
- postoip(fnodes[e], *gnode_ipstart, &me.cur_ip);
- } else {
- new_gnode = 1;
- for (;;) {
- random_ip(gnode_ipstart, fn_hdr->level, fn_hdr->gid,
- FAMILY_LVLS, me.ext_map, 0,
- &me.cur_ip, my_family);
- if (!inet_validate_ip(me.cur_ip))
- break;
- }
- }
- }
-
- if (restricted_mode)
- inet_setip_localaddr(&me.cur_ip, my_family, restricted_class);
- hook_set_all_ips(me.cur_ip, me.cur_ifs, me.cur_ifs_n);
-
- /*
- * Close all the rnl->tcp_sk sockets, 'cause we've changed IP and they
- * aren't valid anymore
- */
- rnl_close_all_sk(rlist);
-
- return new_gnode;
- }
-
-
- /*
- * hook_get_ext_map
- *
- * gets the external map from the rnodes who sent us the free_nodes list.
- * `rq' points to that rnode.
- * `old_ext_map' is the currently used ext_map; it will be merged with the
- * new received map.
- *
- * If a new gnode has been created, 1 is returned.
- */
- int
- hook_get_ext_map(int hook_level, int new_gnode,
- struct rnode_list *rnl, struct free_nodes_hdr *fn_hdr,
- map_gnode ** old_ext_map, quadro_group * old_quadg)
- {
- map_gnode **new_ext_map;
-
- /*
- * Fetch the ext_map from the node who gave us the free nodes list.
- */
- if (!(new_ext_map = get_ext_map(rnl->node, &me.cur_quadg)))
- fatal("None of the rnodes in this area gave me the extern map");
- me.ext_map = new_ext_map;
-
- if (we_are_rehooking && hook_level) {
- int gcount, old_gid;
-
- /*
- * Since we are rehooking, our gnode will change and it will be
- * dismantled, our old gcount has to be decremented from our
- * old ext_map and the one we receive.
- */
- gcount =
- new_ext_map[_EL(hook_level)][old_quadg->gid[hook_level]].
- gcount;
- qspn_dec_gcount((int *) qspn_gnode_count, hook_level + 1, gcount);
-
- old_gid = old_quadg->gid[hook_level];
- new_ext_map[_EL(hook_level)][old_gid].gcount = 0;
- old_ext_map[_EL(hook_level)][old_gid].gcount = 0;
-
- /*
- * We can also delete our old gid, 'cause it doesn't exist
- * anymore
- */
- gmap_node_del(&new_ext_map[_EL(hook_level)][old_gid]);
- gmap_node_del(&old_ext_map[_EL(hook_level)][old_gid]);
- }
-
- /* If we have to create new gnodes, let's do it. */
- if (new_gnode) {
- me.ext_map = old_ext_map;
- old_ext_map = new_ext_map;
- memcpy(old_quadg, &me.cur_quadg, sizeof(quadro_group));
-
- /* Create a new gnode. After this we have a new ip,
- * ext_map and quadro_group */
- create_gnodes(&me.cur_ip,
- we_are_rehooking ? hook_level : fn_hdr->level);
-
- /* Merge the received ext_map with our new empty ext_map */
- merge_ext_maps(me.ext_map, new_ext_map, me.cur_quadg, *old_quadg);
- free_extmap(old_ext_map, FAMILY_LVLS, 0);
-
- return 1;
- }
-
- free_extmap(old_ext_map, FAMILY_LVLS, 0);
- return 0;
- }
-
- /*
- * hook_get_int_map
- *
- * fetch the internal map from a rnode which belongs to our same gnode.
- */
- void
- hook_get_int_map(void)
- {
- struct radar_queue *rq = radar_q;
-
- map_node **merg_map, *new_root;
- int imaps = 0, i;
-
- /*
- * We want a new shiny traslucent internal map
- */
-
- reset_int_map(me.int_map, 0);
- iptoquadg(me.cur_ip, me.ext_map, &me.cur_quadg,
- QUADG_GID | QUADG_GNODE | QUADG_IPSTART);
-
- /* Increment the gnode seeds counter of level one, since
- * we are new in that gnode */
- gnode_inc_seeds(&me.cur_quadg, 0);
-
- /*
- * Fetch the int_map from each rnode and merge them into a
- * single, big, shiny map.
- */
- imaps = 0;
- rq = radar_q;
- merg_map = xzalloc(me.cur_node->links * sizeof(map_node *));
-
- for (i = 0; i < me.cur_node->links; i++) {
- rq = find_node_radar_q((map_node *) me.cur_node->r_node[i].r_node);
-
- if (rq->node->flags & MAP_HNODE)
- continue;
- if (quadg_gids_cmp(rq->quadg, me.cur_quadg, 1))
- /* This node isn't part of our gnode, let's skip it */
- continue;
-
- if ((merg_map[imaps] = get_int_map(rq->node, &new_root))) {
- merge_maps(me.int_map, merg_map[imaps], me.cur_node, new_root);
- imaps++;
- }
- }
- if (!imaps)
- fatal("None of the rnodes in this area gave me the int_map");
-
- for (i = 0; i < imaps; i++)
- free_map(merg_map[i], 0);
- xfree(merg_map);
- }
-
- void
- hook_get_bnode_map(void)
- {
- struct radar_queue *rq = radar_q;
-
- map_bnode **old_bnode_map;
- u_int *old_bnodes;
-
- int e, i;
-
- /*
- * Let's get the bnode map. Fast, fast, quick quick!
- */
- e = 0;
- for (i = 0; i < me.cur_node->links; i++) {
- rq = find_node_radar_q((map_node *) me.cur_node->r_node[i].r_node);
- if (rq->node->flags & MAP_HNODE)
- continue;
- if (quadg_gids_cmp(rq->quadg, me.cur_quadg, 1))
- /* This node isn't part of our gnode, let's skip it */
- continue;
- old_bnode_map = me.bnode_map;
- old_bnodes = me.bmap_nodes;
- me.bnode_map = get_bnode_map(rq->node, &me.bmap_nodes);
- if (me.bnode_map) {
- bmap_levels_free(old_bnode_map, old_bnodes);
- e = 1;
- break;
- } else {
- me.bnode_map = old_bnode_map;
- me.bmap_nodes = old_bnodes;
- }
- }
- if (!e)
- loginfo("None of the rnodes in this area gave me the bnode map.");
-
- }
-
- void
- hook_get_igw(void)
- {
- struct radar_queue *rq = radar_q;
-
- inet_gw **old_igws;
- int *old_igws_counter;
-
- int e, i;
-
- /*
- * Let's get the Internet Gateway list
- */
- e = 0;
- for (i = 0; i < me.cur_node->links; i++) {
- rq = find_node_radar_q((map_node *) me.cur_node->r_node[i].r_node);
- if (rq->node->flags & MAP_HNODE)
- continue;
- if (quadg_gids_cmp(rq->quadg, me.cur_quadg, 1))
- /* This node isn't part of our gnode, let's skip it */
- continue;
-
- old_igws = me.igws;
- old_igws_counter = me.igws_counter;
- me.igws = get_internet_gws(rq->node, &me.igws_counter);
- if (me.igws) {
- free_igws(old_igws, old_igws_counter, FAMILY_LVLS);
- e = 1;
- break;
- } else {
- me.igws = old_igws;
- me.igws_counter = old_igws_counter;
- }
- }
- if (!e) {
- loginfo("None gave me the Internet Gateway list");
- reset_igws(me.igws, me.igws_counter, FAMILY_LVLS);
- }
- }
-
-
- /*
- * hook_finish: final part of the netsukuku_hook process
- */
- void
- hook_finish(int new_gnode, struct free_nodes_hdr *fn_hdr)
- {
- int tracer_levels, i;
-
- /*
- * We must reset the radar_queue because the first radar_scan, used while hooking,
- * has to keep the list of the rnodes' "inet_prefix ip". In this way we know
- * the rnodes' ips even if we haven't an int_map yet.
- */
- reset_radar();
-
- /* Clear the allowed_rnode llist */
- reset_rnode_allowed(&alwd_rnodes, &alwd_rnodes_counter);
-
- /* We have finished the hook */
- me.cur_node->flags &= ~MAP_HNODE;
-
- /* Disable the filter */
- op_filter_reset(OP_FILTER_ALLOW);
-
- if (new_gnode) {
- if (!me.cur_node->links)
- /*
- * We are a node lost in the desert, so we don't send
- * anything because nobody is listening
- */
- tracer_levels = 0;
- else
- /*
- * We are a new gnode, so we send the tracer in all higher
- * levels
- */
- tracer_levels = fn_hdr->level;
- } else {
- /*
- * We are just a normal node inside a gnode, let's notice only
- * the other nodes in this gnode.
- */
- tracer_levels = 2;
- }
-
- /*
- * Initialize me.my_igws
- */
- if (server_opt.share_internet) {
- free_my_igws(&me.my_igws);
- init_my_igws(me.igws, me.igws_counter, &me.my_igws,
- me.my_bandwidth, me.cur_node, &me.cur_quadg);
- }
-
- loginfo("Starting the second radar scan before sending our"
- " first tracer_pkt");
- if (radar_scan(0))
- fatal("%s:%d: Scan of the area failed. Cannot continue.",
- ERROR_POS);
-
- /*
- * Now we send a simple tracer_pkt in all the level we have to. This pkt
- * is just to say <<Hey there, I'm here, alive>>, thus the other nodes
- * of the gnode will have the basic routes to reach us.
- * Note that this is done only at the first time we hook.
- */
- if (!we_are_rehooking) {
- usleep(rand_range(0, 999999));
- tracer_pkt_start_mutex = 0;
- for (i = 1; i < tracer_levels; i++)
- tracer_pkt_start(i - 1);
- }
-
- /* Let's fill the krnl routing table */
- loginfo("Filling the kernel routing table");
-
- rt_full_update(0);
- if (restricted_mode && (server_opt.use_shared_inet ||
- server_opt.share_internet))
- igw_replace_def_igws(me.igws, me.igws_counter,
- me.my_igws, me.cur_quadg.levels, my_family);
-
- /* (Re)Hook completed */
- loginfo("%sook completed", we_are_rehooking ? "Reh" : "H");
-
- we_are_rehooking = 0;
- }
-
- /*
- * netsukuku_hook: hooks/rehooks at an existing gnode or creates a new one.
- * `hook_level' specifies at what level we are hooking, generally it is 0.
- * If `hook_gnode' is not null, netsukuku_hook will try to hook only to the
- * rnodes which belongs to the `hook_gnode' at `hook_level' level.
- */
- int
- netsukuku_hook(map_gnode * hook_gnode, int hook_level)
- {
- struct rnode_list *rnl = rlist;
- struct free_nodes_hdr fn_hdr;
-
- inet_prefix gnode_ipstart, old_ip;
- quadro_group old_quadg;
-
- int ret = 0, new_gnode = 0;
- u_char fnodes[MAXGROUPNODE];
-
- /* Save our current IP before resetting */
- inet_copy(&old_ip, &me.cur_ip);
- memcpy(&old_quadg, &me.cur_quadg, sizeof(quadro_group));
-
- /* Reset the hook */
- if (total_hooks) {
- hook_reset();
- we_are_rehooking = 1;
- }
- total_hooks++;
-
- /*
- * * The beginning * *
- */
- loginfo("The %s begins. Starting to scan the area",
- we_are_rehooking ? "rehook" : "hook");
- new_gnode = hook_first_radar_scan(hook_gnode, hook_level, &old_quadg);
- if (new_gnode)
- goto finish;
-
- /*
- * Get the free nodes list
- */
- qspn_backup_gcount(qspn_old_gcount, (int *) qspn_gnode_count);
- new_gnode = hook_get_free_nodes(hook_level, &fn_hdr, fnodes,
- &gnode_ipstart, qspn_gnode_count,
- &rnl);
- if (new_gnode)
- goto finish;
-
- /*
- * Choose a new IP
- */
- new_gnode = hook_choose_new_ip(hook_gnode, hook_level, &fn_hdr, fnodes,
- &gnode_ipstart);
-
- /*
- * Get the external map
- */
- new_gnode = hook_get_ext_map(hook_level, new_gnode, rnl, &fn_hdr,
- me.ext_map, &old_quadg);
- if (new_gnode)
- goto finish;
-
- /*
- * Get the internal map
- */
- hook_get_int_map();
-
- /*
- * Fetch the bnode map
- */
- hook_get_bnode_map();
-
- /*
- * If we are in restricted mode, get the Internet Gateways
- */
- if (restricted_mode && (server_opt.use_shared_inet ||
- server_opt.share_internet))
- hook_get_igw();
-
- /*
- * And that's all, clean the mess
- */
-
- if (free_the_tmp_cur_node) {
- xfree(me.cur_node);
- free_the_tmp_cur_node = 0;
- }
- me.cur_node = &me.int_map[me.cur_quadg.gid[0]];
- map_node_del(me.cur_node);
- me.cur_node->flags &= ~MAP_VOID;
- me.cur_node->flags |= MAP_ME;
-
- /* We need a fresh me.cur_node */
- refresh_hook_root_node();
-
- finish:
- hook_finish(new_gnode, &fn_hdr);
- return ret;
- }
-
- /*
- * And this is the end my dear.
- */
|