123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227 |
- // SoftEther VPN Source Code
- // Cedar Communication Module
- //
- // SoftEther VPN Server, Client and Bridge are free software under GPLv2.
- //
- // Copyright (c) 2012-2014 Daiyuu Nobori.
- // Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
- // Copyright (c) 2012-2014 SoftEther Corporation.
- //
- // All Rights Reserved.
- //
- // http://www.softether.org/
- //
- // Author: Daiyuu Nobori
- // Comments: Tetsuo Sugiyama, Ph.D.
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // version 2 as published by the Free Software Foundation.
- //
- // This program 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. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License version 2
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- // THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
- // AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
- //
- //
- // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
- // UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
- // MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
- // SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
- // SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
- // CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
- // DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
- // MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
- // SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
- // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
- // EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
- // JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
- // AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
- // THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
- //
- // USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
- // SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
- // PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
- // COUNTRIES MIGHT BE RESTRICTED.
- //
- //
- // SOURCE CODE CONTRIBUTION
- // ------------------------
- //
- // Your contribution to SoftEther VPN Project is much appreciated.
- // Please send patches to us through GitHub.
- // Read the SoftEther VPN Patch Acceptance Policy in advance:
- // http://www.softether.org/5-download/src/9.patch
- //
- //
- // DEAR SECURITY EXPERTS
- // ---------------------
- //
- // If you find a bug or a security vulnerability please kindly inform us
- // about the problem immediately so that we can fix the security problem
- // to protect a lot of users around the world as soon as possible.
- //
- // Our e-mail address for security reports is:
- // softether-vpn-security [at] softether.org
- //
- // Please note that the above e-mail address is not a technical support
- // inquiry address. If you need technical assistance, please visit
- // http://www.softether.org/ and ask your question on the users forum.
- //
- // Thank you for your cooperation.
- //
- //
- // NO MEMORY OR RESOURCE LEAKS
- // ---------------------------
- //
- // The memory-leaks and resource-leaks verification under the stress
- // test has been passed before release this source code.
- // Virtual.c
- // User-mode virtual host program
- #include "CedarPch.h"
- static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- static char v_vgs_hostname[256] = {0};
- static char secure_nat_target_hostname[MAX_SIZE] = {0};
- // Specify the destination host name to be used for connectivity testing in SecureNAT
- void NnSetSecureNatTargetHostname(char *name)
- {
- // Validate arguments
- if (name == NULL)
- {
- return;
- }
- StrCpy(secure_nat_target_hostname, sizeof(secure_nat_target_hostname), name);
- }
- // Delete the oldest NAT session if necessary
- void NnDeleteOldestNatSessionIfNecessary(NATIVE_NAT *t, UINT ip, UINT protocol)
- {
- UINT current_num;
- UINT max_sessions = 0;
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- if (t->v->HubOption != NULL)
- {
- HUB_OPTION *o = t->v->HubOption;
- switch (protocol)
- {
- case NAT_TCP:
- max_sessions = o->SecureNAT_MaxTcpSessionsPerIp;
- break;
- case NAT_UDP:
- max_sessions = o->SecureNAT_MaxUdpSessionsPerIp;
- break;
- case NAT_ICMP:
- max_sessions = o->SecureNAT_MaxIcmpSessionsPerIp;
- break;
- }
- }
- if (max_sessions == 0)
- {
- return;
- }
- current_num = NnGetNumNatEntriesPerIp(t, ip, protocol);
- if (current_num >= max_sessions)
- {
- NnDeleteOldestNatSession(t, ip, protocol);
- }
- }
- // Delete the oldest NAT session
- void NnDeleteOldestNatSession(NATIVE_NAT *t, UINT ip, UINT protocol)
- {
- NATIVE_NAT_ENTRY *e;
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- e = NnGetOldestNatEntryOfIp(t, ip, protocol);
- if (e != NULL)
- {
- NnDeleteSession(t, e);
- }
- }
- // Get the oldest NAT session
- NATIVE_NAT_ENTRY *NnGetOldestNatEntryOfIp(NATIVE_NAT *t, UINT ip, UINT protocol)
- {
- UINT i;
- NATIVE_NAT_ENTRY *oldest = NULL;
- UINT64 oldest_tick = 0xFFFFFFFFFFFFFFFFULL;
- // Validate arguments
- if (t == NULL)
- {
- return NULL;
- }
- for (i = 0;i < LIST_NUM(t->NatTableForRecv->AllList);i++)
- {
- NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForRecv->AllList, i);
- if (e->SrcIp == ip)
- {
- if (e->Protocol == protocol)
- {
- if (e->LastCommTime <= oldest_tick)
- {
- oldest_tick = e->LastCommTime;
- oldest = e;
- }
- }
- }
- }
- return oldest;
- }
- // Get the number of NAT sessions per IP address
- UINT NnGetNumNatEntriesPerIp(NATIVE_NAT *t, UINT src_ip, UINT protocol)
- {
- UINT ret = 0;
- UINT i;
- // Validate arguments
- if (t == NULL)
- {
- return 0;
- }
- for (i = 0;i < LIST_NUM(t->NatTableForRecv->AllList);i++)
- {
- NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForRecv->AllList, i);
- if (e->SrcIp == src_ip)
- {
- if (e->Protocol == protocol)
- {
- ret++;
- }
- }
- }
- return ret;
- }
- // Delete the old NAT sessions
- void NnDeleteOldSessions(NATIVE_NAT *t)
- {
- UINT i;
- LIST *o;
- UINT64 now;
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- o = NULL;
- now = t->v->Now;
- for (i = 0;i < LIST_NUM(t->NatTableForSend->AllList);i++)
- {
- NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForSend->AllList, i);
- UINT64 timeout;
- if (e->Status == NAT_TCP_CONNECTED || e->Status == NAT_TCP_ESTABLISHED)
- {
- timeout = e->LastCommTime + (UINT64)(e->Protocol == NAT_TCP ? t->v->NatTcpTimeout : t->v->NatUdpTimeout);
- }
- else
- {
- timeout = e->LastCommTime + (UINT64)NN_TIMEOUT_FOR_UNESTBALISHED_TCP;
- }
- if (timeout < now)
- {
- // Time-out occurs
- if (o == NULL)
- {
- o = NewListFast(NULL);
- }
- Add(o, e);
- }
- }
- if (o != NULL)
- {
- for (i = 0;i < LIST_NUM(o);i++)
- {
- NATIVE_NAT_ENTRY *e = LIST_DATA(o, i);
- NnDeleteSession(t, e);
- }
- ReleaseList(o);
- }
- }
- // Delete the NAT entry
- void NnDeleteSession(NATIVE_NAT *t, NATIVE_NAT_ENTRY *e)
- {
- // Validate arguments
- if (t == NULL || e == NULL)
- {
- return;
- }
- switch (e->Protocol)
- {
- case NAT_TCP:
- // Send a RST to the client side
- SendTcp(t->v, e->DestIp, e->DestPort, e->SrcIp, e->SrcPort,
- e->LastAck, e->LastSeq + (e->Status == NAT_TCP_CONNECTING ? 1 : 0), TCP_RST | TCP_ACK, 0, 0, NULL, 0);
- NLog(t->v, "LH_NAT_TCP_DELETED", e->Id);
- break;
- case NAT_UDP:
- NLog(t->v, "LH_NAT_UDP_DELETED", e->Id);
- break;
- case NAT_ICMP:
- Debug("NAT ICMP %u Deleted.", e->Id);
- break;
- }
- DeleteHash(t->NatTableForSend, e);
- DeleteHash(t->NatTableForRecv, e);
- Free(e);
- }
- // Poll the IP combining object
- void NnPollingIpCombine(NATIVE_NAT *t)
- {
- LIST *o;
- UINT i;
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- // Discard the old combining object
- o = NULL;
- for (i = 0;i < LIST_NUM(t->IpCombine);i++)
- {
- IP_COMBINE *c = LIST_DATA(t->IpCombine, i);
- if (c->Expire < t->v->Now)
- {
- if (o == NULL)
- {
- o = NewListFast(NULL);
- }
- Add(o, c);
- }
- }
- if (o != NULL)
- {
- for (i = 0;i < LIST_NUM(o);i++)
- {
- IP_COMBINE *c = LIST_DATA(o, i);
- // Remove from the list
- Delete(t->IpCombine, c);
- // Release the memory
- NnFreeIpCombine(t, c);
- }
- ReleaseList(o);
- }
- }
- // Combine the IP packet received to the IP combining object
- void NnCombineIp(NATIVE_NAT *t, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet, UCHAR *head_ip_header_data, UINT head_ip_header_size)
- {
- UINT i;
- IP_PART *p;
- UINT need_size;
- UINT data_size_delta;
- // Validate arguments
- if (c == NULL || data == NULL)
- {
- return;
- }
- // Check the size and offset
- if ((offset + size) > 65535)
- {
- // Do not process a packet larger than 64Kbytes
- return;
- }
- if (last_packet == false && c->Size != 0)
- {
- if ((offset + size) > c->Size)
- {
- // Do not process a packet larger than the packet size
- return;
- }
- }
- if (head_ip_header_data != NULL && head_ip_header_size >= sizeof(IPV4_HEADER))
- {
- if (c->HeadIpHeaderData == NULL)
- {
- c->HeadIpHeaderData = Clone(head_ip_header_data, head_ip_header_size);
- c->HeadIpHeaderDataSize = head_ip_header_size;
- }
- }
- need_size = offset + size;
- data_size_delta = c->DataReserved;
- // Ensure sufficient if the buffer is insufficient
- while (c->DataReserved < need_size)
- {
- c->DataReserved = c->DataReserved * 4;
- c->Data = ReAlloc(c->Data, c->DataReserved);
- }
- data_size_delta = c->DataReserved - data_size_delta;
- t->CurrentIpQuota += data_size_delta;
- // Overwrite the data into the buffer
- Copy(((UCHAR *)c->Data) + offset, data, size);
- if (last_packet)
- {
- // If No More Flagment packet arrives, the size of this datagram is finalized
- c->Size = offset + size;
- }
- // Check the overlap between the region which is represented by the offset and size of the
- // existing received list and the region which is represented by the offset and size
- for (i = 0;i < LIST_NUM(c->IpParts);i++)
- {
- UINT moving_size;
- IP_PART *p = LIST_DATA(c->IpParts, i);
- // Check the overlapping between the existing area and head area
- if ((p->Offset <= offset) && ((p->Offset + p->Size) > offset))
- {
- // Compress behind the offset of this packet since a duplication is
- // found in the first part with the existing packet and this packet
- if ((offset + size) <= (p->Offset + p->Size))
- {
- // This packet is buried in the existing packet
- size = 0;
- }
- else
- {
- // Retral region is not overlapped
- moving_size = p->Offset + p->Size - offset;
- offset += moving_size;
- size -= moving_size;
- }
- }
- if ((p->Offset < (offset + size)) && ((p->Offset + p->Size) >= (offset + size)))
- {
- // Compress the size of this packet forward because a duplication is
- // found between the posterior portion the existing packet and this packet
- moving_size = p->Offset + p->Size - offset - size;
- size -= moving_size;
- }
- if ((p->Offset >= offset) && ((p->Offset + p->Size) <= (offset + size)))
- {
- // This packet was overwritten to completely hunched over a existing packet
- p->Size = 0;
- }
- }
- if (size != 0)
- {
- // Register this packet
- p = ZeroMalloc(sizeof(IP_PART));
- p->Offset = offset;
- p->Size = size;
- Add(c->IpParts, p);
- }
- if (c->Size != 0)
- {
- // Get the total size of the data portion list already received
- UINT total_size = 0;
- UINT i;
- for (i = 0;i < LIST_NUM(c->IpParts);i++)
- {
- IP_PART *p = LIST_DATA(c->IpParts, i);
- total_size += p->Size;
- }
- if (total_size == c->Size)
- {
- // Received whole of the IP packet
- NnIpReceived(t, c->SrcIP, c->DestIP, c->Protocol, c->Data, c->Size, c->Ttl,
- c->HeadIpHeaderData, c->HeadIpHeaderDataSize, c->MaxL3Size);
- // Release the combining object
- NnFreeIpCombine(t, c);
- // Remove from the combining object list
- Delete(t->IpCombine, c);
- }
- }
- }
- // Release the IP combining object
- void NnFreeIpCombine(NATIVE_NAT *t, IP_COMBINE *c)
- {
- UINT i;
- // Validate arguments
- if (c == NULL)
- {
- return;
- }
- // Release the data
- t->CurrentIpQuota -= c->DataReserved;
- Free(c->Data);
- // Release the partial list
- for (i = 0;i < LIST_NUM(c->IpParts);i++)
- {
- IP_PART *p = LIST_DATA(c->IpParts, i);
- Free(p);
- }
- Free(c->HeadIpHeaderData);
- ReleaseList(c->IpParts);
- Free(c);
- }
- // Search the IP combining list
- IP_COMBINE *NnSearchIpCombine(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol)
- {
- IP_COMBINE *c, tt;
- // Validate arguments
- if (t == NULL)
- {
- return NULL;
- }
- tt.DestIP = dest_ip;
- tt.SrcIP = src_ip;
- tt.Id = id;
- tt.Protocol = protocol;
- c = Search(t->IpCombine, &tt);
- return c;
- }
- // Insert by creating a new object to the IP combining list
- IP_COMBINE *NnInsertIpCombine(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast, UCHAR ttl, bool src_is_localmac)
- {
- IP_COMBINE *c;
- // Validate arguments
- if (t == NULL)
- {
- return NULL;
- }
- // Examine the quota
- if ((t->CurrentIpQuota + IP_COMBINE_INITIAL_BUF_SIZE) > IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA)
- {
- // IP packet can not be stored any more
- return NULL;
- }
- c = ZeroMalloc(sizeof(IP_COMBINE));
- c->SrcIsLocalMacAddr = src_is_localmac;
- c->DestIP = dest_ip;
- c->SrcIP = src_ip;
- c->Id = id;
- c->Expire = t->v->Now + (UINT64)IP_COMBINE_TIMEOUT;
- c->Size = 0;
- c->IpParts = NewList(NULL);
- c->Protocol = protocol;
- c->MacBroadcast = mac_broadcast;
- c->Ttl = ttl;
- // Secure the memory
- c->DataReserved = IP_COMBINE_INITIAL_BUF_SIZE;
- c->Data = Malloc(c->DataReserved);
- t->CurrentIpQuota += c->DataReserved;
- Insert(t->IpCombine, c);
- return c;
- }
- // Initialize the IP combining list
- void NnInitIpCombineList(NATIVE_NAT *t)
- {
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- t->IpCombine = NewList(CompareIpCombine);
- }
- // Release the IP combining list
- void NnFreeIpCombineList(NATIVE_NAT *t)
- {
- UINT i;
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- for (i = 0;i < LIST_NUM(t->IpCombine);i++)
- {
- IP_COMBINE *c = LIST_DATA(t->IpCombine, i);
- NnFreeIpCombine(t, c);
- }
- ReleaseList(t->IpCombine);
- }
- // A TCP packet is received
- void NnTcpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size)
- {
- TCP_HEADER *tcp;
- UCHAR *payload;
- UINT payload_size;
- UINT tcp_header_size;
- // Validate arguments
- if (t == NULL || data == NULL)
- {
- return;
- }
- // TCP header
- if (size < sizeof(TCP_HEADER))
- {
- return;
- }
- tcp = (TCP_HEADER *)data;
- // Get the TCP header size
- tcp_header_size = TCP_GET_HEADER_SIZE(tcp) * 4;
- if (size < tcp_header_size || tcp_header_size < sizeof(TCP_HEADER))
- {
- return;
- }
- // Payload
- payload = ((UCHAR *)data) + tcp_header_size;
- payload_size = size - tcp_header_size;
- // Search the port from the NAT table
- if (true)
- {
- NATIVE_NAT_ENTRY tt;
- NATIVE_NAT_ENTRY *e;
- NnSetNat(&tt, NAT_TCP, 0, 0, src_ip, Endian16(tcp->SrcPort), dest_ip, Endian16(tcp->DstPort));
- e = SearchHash(t->NatTableForRecv, &tt);
- if (e != NULL)
- {
- // Last communication time
- e->LastCommTime = t->v->Now;
- e->TotalRecv += (UINT64)size;
- // Rewrite the TCP header
- tcp->Checksum = 0;
- tcp->DstPort = Endian16(e->SrcPort);
- if (tcp->Flag & TCP_FIN || tcp->Flag & TCP_RST)
- {
- // Disconnect
- e->Status = NAT_TCP_WAIT_DISCONNECT;
- }
- if (tcp->Flag & TCP_SYN && tcp->Flag & TCP_ACK)
- {
- // Connection complete
- if (e->Status != NAT_TCP_WAIT_DISCONNECT)
- {
- e->Status = NAT_TCP_ESTABLISHED;
- }
- }
- e->LastSeq = Endian32(tcp->AckNumber);
- e->LastAck = Endian32(tcp->SeqNumber);
- // Checksum recalculation
- tcp->Checksum = CalcChecksumForIPv4(src_ip, e->SrcIp, IP_PROTO_TCP, tcp, size, 0);
- // IP transmission
- SendIp(t->v, e->SrcIp, src_ip, IP_PROTO_TCP, tcp, size);
- }
- }
- }
- // An ICMP packet has been received
- void NnIcmpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size)
- {
- ICMP_HEADER *icmp;
- // Validate arguments
- if (t == NULL || data == NULL)
- {
- return;
- }
- if (ttl == 0)
- {
- ttl = 1;
- }
- // ICMP header
- if (size < sizeof(ICMP_HEADER))
- {
- return;
- }
- icmp = (ICMP_HEADER *)data;
- if (icmp->Type == ICMP_TYPE_ECHO_RESPONSE)
- {
- UCHAR *payload;
- UINT payload_size;
- ICMP_ECHO *echo;
- NATIVE_NAT_ENTRY tt, *e;
- // Echo Response
- echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
- if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- return;
- }
- payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
- payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- // Search the NAT
- NnSetNat(&tt, NAT_ICMP, 0, 0, 0, 0, dest_ip, Endian16(echo->Identifier));
- e = SearchHash(t->NatTableForRecv, &tt);
- if (e != NULL)
- {
- // Rewrite the header
- icmp->Checksum = 0;
- echo->Identifier = Endian16(e->SrcPort);
- icmp->Checksum = IpChecksum(icmp, size);
- e->LastCommTime = t->v->Now;
- e->TotalRecv += (UINT64)size;
- // Transmission
- SendIpEx(t->v, e->SrcIp, src_ip, IP_PROTO_ICMPV4, icmp, size, MAX(ttl - 1, 1));
- }
- }
- else if (icmp->Type == ICMP_TYPE_ECHO_REQUEST)
- {
- UCHAR *payload;
- UINT payload_size;
- ICMP_ECHO *echo;
- // Echo Response
- echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
- if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- return;
- }
- payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
- payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- if (dest_ip == t->PublicIP)
- {
- // Respond as soon as the Echo Request is received at the public side interface
- ICMP_HEADER *ret_icmp;
- ICMP_ECHO *ret_echo;
- UINT ret_size = sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size;
- ret_icmp = ZeroMalloc(ret_size);
- ret_echo = (ICMP_ECHO *)(((UCHAR *)ret_icmp) + sizeof(ICMP_HEADER));
- ret_icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
- ret_icmp->Code = icmp->Code;
- ret_echo->Identifier = echo->Identifier;
- ret_echo->SeqNo = echo->SeqNo;
- Copy((UCHAR *)ret_icmp + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO),
- payload, payload_size);
- ret_icmp->Checksum = IpChecksum(ret_icmp, ret_size);
- NnIpSendForInternet(t, IP_PROTO_ICMPV4, 0, dest_ip, src_ip, ret_icmp, ret_size, max_l3_size);
- Free(ret_icmp);
- }
- }
- else
- {
- if (icmp->Type == ICMP_TYPE_DESTINATION_UNREACHABLE || icmp->Type == ICMP_TYPE_TIME_EXCEEDED)
- {
- // Rewrite the Src IP of the IPv4 header of the ICMP response packet
- if (size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + sizeof(IPV4_HEADER)))
- {
- IPV4_HEADER *orig_ipv4 = (IPV4_HEADER *)(((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- UINT orig_ipv4_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- UINT orig_ipv4_header_size = GetIpHeaderSize((UCHAR *)orig_ipv4, orig_ipv4_size);
- if (orig_ipv4_header_size >= sizeof(IPV4_HEADER) && orig_ipv4_size >= orig_ipv4_header_size)
- {
- if (orig_ipv4->Protocol == IP_PROTO_ICMPV4)
- {
- // Search the inner ICMP header
- UINT inner_icmp_size = orig_ipv4_size - orig_ipv4_header_size;
- if (inner_icmp_size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- ICMP_HEADER *inner_icmp = (ICMP_HEADER *)(((UCHAR *)data) +
- sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + orig_ipv4_header_size);
- if (inner_icmp->Type == ICMP_TYPE_ECHO_REQUEST)
- {
- ICMP_ECHO *inner_echo = (ICMP_ECHO *)(((UCHAR *)inner_icmp) + sizeof(ICMP_HEADER));
- NATIVE_NAT_ENTRY tt, *e;
- // Search for the existing NAT table entry
- NnSetNat(&tt, NAT_ICMP, 0, 0, 0, 0, orig_ipv4->SrcIP, Endian16(inner_echo->Identifier));
- e = SearchHash(t->NatTableForRecv, &tt);
- if (e != NULL)
- {
- e->LastCommTime = t->v->Now;
- // Rewrite the inner IP packet and the ICMP header according to the NAT table
- inner_echo->Identifier = Endian16(e->SrcPort);
- inner_icmp->Checksum = 0;
- orig_ipv4->SrcIP = e->SrcIp;
- orig_ipv4->Checksum = 0;
- orig_ipv4->Checksum = IpChecksum(orig_ipv4, orig_ipv4_header_size);
- // Rewrite the outer ICMP header
- if (true)
- {
- UCHAR *payload;
- UINT payload_size;
- ICMP_ECHO *echo;
- // Echo Response
- echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
- if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- return;
- }
- payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
- payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- // Rewrite the header
- icmp->Checksum = 0;
- echo->Identifier = Endian16(e->SrcPort);
- icmp->Checksum = IpChecksum(icmp, size);
- // Transmission
- SendIpEx(t->v, e->SrcIp, src_ip, IP_PROTO_ICMPV4, icmp, size, MAX(ttl - 1, 1));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- // An UDP packet has been received
- void NnUdpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size)
- {
- UDP_HEADER *udp;
- UCHAR *payload;
- UINT payload_size;
- // Validate arguments
- if (t == NULL || data == NULL)
- {
- return;
- }
- // UDP header
- if (size <= sizeof(UDP_HEADER))
- {
- return;
- }
- udp = (UDP_HEADER *)data;
- // Payload
- payload = ((UCHAR *)data) + sizeof(UDP_HEADER);
- payload_size = size - sizeof(UDP_HEADER);
- // Inspect the payload size
- if (payload_size < (Endian16(udp->PacketLength) - sizeof(UDP_HEADER)))
- {
- return;
- }
- // Truncate the payload
- payload_size = Endian16(udp->PacketLength) - sizeof(UDP_HEADER);
- // Search the port number from the NAT table
- if (true)
- {
- NATIVE_NAT_ENTRY tt;
- NATIVE_NAT_ENTRY *e;
- NnSetNat(&tt, NAT_UDP, 0, 0, 0, 0, dest_ip, Endian16(udp->DstPort));
- e = SearchHash(t->NatTableForRecv, &tt);
- if (e != NULL)
- {
- // Last communication time
- e->LastCommTime = t->v->Now;
- e->TotalRecv += (UINT64)payload_size;
- // Deliver to the client by rewriting the port number
- SendUdp(t->v, e->SrcIp, e->SrcPort, src_ip, Endian16(udp->SrcPort),
- payload, payload_size);
- }
- }
- }
- // A combined IP packet is received
- void NnIpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size,
- UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
- {
- // Validate arguments
- if (t == NULL || data == NULL)
- {
- return;
- }
- if (dest_ip != t->PublicIP)
- {
- // Destination IP is not a unicast
- return;
- }
- switch (protocol)
- {
- case IP_PROTO_UDP:
- // UDP
- NnUdpReceived(t, src_ip, dest_ip, data, size, ttl, max_l3_size);
- break;
- case IP_PROTO_TCP:
- // TCP
- NnTcpReceived(t, src_ip, dest_ip, data, size, ttl, max_l3_size);
- break;
- case IP_PROTO_ICMPV4:
- // ICMP
- NnIcmpReceived(t, src_ip, dest_ip, data, size, ttl, max_l3_size);
- break;
- }
- }
- // Received an IP packet
- void NnFragmentedIpReceived(NATIVE_NAT *t, PKT *packet)
- {
- IPV4_HEADER *ip;
- void *data;
- UINT data_size_recved;
- UINT size;
- UINT ipv4_header_size;
- bool last_packet = false;
- UINT l3_size = 0;
- UCHAR *head_ip_header_data = NULL;
- UINT head_ip_header_size = 0;
- // Validate arguments
- if (t == NULL || packet == NULL)
- {
- return;
- }
- ip = packet->L3.IPv4Header;
- // Get the size of the IPv4 header
- ipv4_header_size = IPV4_GET_HEADER_LEN(packet->L3.IPv4Header) * 4;
- head_ip_header_size = ipv4_header_size;
- // Get the pointer to the data
- data = ((UCHAR *)packet->L3.PointerL3) + ipv4_header_size;
- // Get the data size
- size = l3_size = Endian16(ip->TotalLength);
- if (size <= ipv4_header_size)
- {
- // There is no data
- return;
- }
- size -= ipv4_header_size;
- // Get the size of data actually received
- data_size_recved = packet->PacketSize - (ipv4_header_size + MAC_HEADER_SIZE);
- if (data_size_recved < size)
- {
- // Data insufficient (It may be missing on the way)
- return;
- }
- if (IPV4_GET_OFFSET(ip) == 0 && (IPV4_GET_FLAGS(ip) & 0x01) == 0)
- {
- // Because this packet has not been fragmented, it can be passed to the upper layer immediately
- head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
- NnIpReceived(t, ip->SrcIP, ip->DstIP, ip->Protocol, data, size, ip->TimeToLive,
- head_ip_header_data, head_ip_header_size, l3_size);
- }
- else
- {
- // This packet is necessary to combine because it is fragmented
- UINT offset = IPV4_GET_OFFSET(ip) * 8;
- IP_COMBINE *c = NnSearchIpCombine(t, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol);
- if (offset == 0)
- {
- head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
- }
- last_packet = ((IPV4_GET_FLAGS(ip) & 0x01) == 0 ? true : false);
- if (c != NULL)
- {
- // It is the second or subsequent packet
- c->MaxL3Size = MAX(c->MaxL3Size, l3_size);
- NnCombineIp(t, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
- }
- else
- {
- // Create a combining object because it is the first packet
- c = NnInsertIpCombine(
- t, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol, packet->BroadcastPacket,
- ip->TimeToLive, false);
- c->MaxL3Size = MAX(c->MaxL3Size, l3_size);
- if (c != NULL)
- {
- NnCombineIp(t, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
- }
- }
- }
- }
- // Layer 2 packet processing
- void NnLayer2(NATIVE_NAT *t, PKT *packet)
- {
- // Validate arguments
- if (t == NULL || packet == NULL)
- {
- return;
- }
- if (packet->TypeL3 == L3_IPV4)
- {
- // IPv4
- NnFragmentedIpReceived(t, packet);
- }
- }
- // Extract the received packets of native NAT, and deliver it to the VPN client
- void NnPoll(NATIVE_NAT *t)
- {
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- LockQueue(t->RecvQueue);
- {
- while (true)
- {
- PKT *pkt = GetNext(t->RecvQueue);
- if (pkt == NULL)
- {
- break;
- }
- NnLayer2(t, pkt);
- FreePacketWithData(pkt);
- }
- }
- UnlockQueue(t->RecvQueue);
- if (t->SendStateChanged)
- {
- TUBE *halt_tube = NULL;
- Lock(t->Lock);
- {
- if (t->HaltTube != NULL)
- {
- halt_tube = t->HaltTube;
- AddRef(halt_tube->Ref);
- }
- }
- Unlock(t->Lock);
- if (halt_tube != NULL)
- {
- TubeFlushEx(halt_tube, true);
- t->SendStateChanged = false;
- ReleaseTube(halt_tube);
- }
- }
- NnPollingIpCombine(t);
- NnDeleteOldSessions(t);
- }
- // Send a fragmented IP packet to the Internet
- void NnIpSendFragmentedForInternet(NATIVE_NAT *t, UCHAR ip_protocol, UINT src_ip, UINT dest_ip, USHORT id, USHORT total_size,
- USHORT offset, void *data, UINT size, UCHAR ttl)
- {
- UCHAR *buf;
- IPV4_HEADER *ip;
- BLOCK *b;
- // Validate arguments
- if (t == NULL || data == NULL)
- {
- return;
- }
- // Memory allocation
- buf = Malloc(size + IP_HEADER_SIZE);
- ip = (IPV4_HEADER *)&buf[0];
- // IP header construction
- ip->VersionAndHeaderLength = 0;
- IPV4_SET_VERSION(ip, 4);
- IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
- ip->TypeOfService = DEFAULT_IP_TOS;
- ip->TotalLength = Endian16((USHORT)(size + IP_HEADER_SIZE));
- ip->Identification = Endian16(id);
- ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
- IPV4_SET_OFFSET(ip, (offset / 8));
- if ((offset + size) >= total_size)
- {
- IPV4_SET_FLAGS(ip, 0x00);
- }
- else
- {
- IPV4_SET_FLAGS(ip, 0x01);
- }
- ip->TimeToLive = (ttl == 0 ? DEFAULT_IP_TTL : ttl);
- ip->Protocol = ip_protocol;
- ip->Checksum = 0;
- ip->SrcIP = src_ip;
- ip->DstIP = dest_ip;
- // Checksum calculation
- ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
- // Data copy
- Copy(buf + IP_HEADER_SIZE, data, size);
- // Transmission
- b = NewBlock(buf, size + IP_HEADER_SIZE, 0);
- LockQueue(t->SendQueue);
- {
- if (t->SendQueue->num_item <= NN_MAX_QUEUE_LENGTH)
- {
- InsertQueue(t->SendQueue, b);
- t->SendStateChanged = true;
- }
- else
- {
- FreeBlock(b);
- }
- }
- UnlockQueue(t->SendQueue);
- }
- // Send an IP packet to the Internet
- void NnIpSendForInternet(NATIVE_NAT *t, UCHAR ip_protocol, UCHAR ttl, UINT src_ip, UINT dest_ip, void *data, UINT size, UINT max_l3_size)
- {
- UINT mss = 0;
- UCHAR *buf;
- USHORT offset;
- USHORT id;
- USHORT total_size;
- UINT size_of_this_packet;
- // Validate arguments
- if (t == NULL || data == NULL)
- {
- return;
- }
- // Maximum segment size
- if (max_l3_size > IP_HEADER_SIZE)
- {
- mss = max_l3_size - IP_HEADER_SIZE;
- }
- if (mss == 0)
- {
- mss = t->v->IpMss;
- }
- mss = MAX(mss, 1000);
- // Buffer
- buf = (UCHAR *)data;
- // ID
- id = (t->NextId++);
- // Total size
- total_size = (USHORT)size;
- // Start to fragment
- offset = 0;
- while (true)
- {
- bool last_packet = false;
- // Get the size of this packet
- size_of_this_packet = MIN((USHORT)mss, (total_size - offset));
- if ((offset + (USHORT)size_of_this_packet) == total_size)
- {
- last_packet = true;
- }
- // Transmit the fragmented packet
- NnIpSendFragmentedForInternet(t, ip_protocol, src_ip, dest_ip, id, total_size, offset,
- buf + offset, size_of_this_packet, ttl);
- if (last_packet)
- {
- break;
- }
- offset += (USHORT)size_of_this_packet;
- }
- }
- // Communication of ICMP towards the Internet
- void NnIcmpEchoRecvForInternet(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
- {
- NATIVE_NAT_ENTRY tt;
- NATIVE_NAT_ENTRY *e;
- NATIVE_NAT *t;
- USHORT src_port;
- ICMP_HEADER *old_icmp_header;
- ICMP_ECHO *old_icmp_echo;
- ICMP_HEADER *icmp;
- ICMP_ECHO *echo;
- UCHAR *payload_data;
- UINT payload_size;
- // Validate arguments
- if (NnIsActive(v) == false || icmp_data == NULL)
- {
- return;
- }
- t = v->NativeNat;
- old_icmp_header = (ICMP_HEADER *)icmp_data;
- old_icmp_echo = (ICMP_ECHO *)(((UCHAR *)icmp_data) + sizeof(ICMP_HEADER));
- if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- return;
- }
- payload_data = ((UCHAR *)icmp_data) + (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- payload_size = icmp_size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- if (dest_ip == v->HostIP)
- {
- // Respond because it is addressed to me
- VirtualIcmpEchoSendResponse(v, dest_ip, src_ip, Endian16(old_icmp_echo->Identifier),
- Endian16(old_icmp_echo->SeqNo), payload_data, payload_size);
- return;
- }
- if (ttl <= 1)
- {
- // Reply the Time Exceeded immediately for the packet whose TTL is 1
- UINT reply_size = sizeof(ICMP_HEADER) + 4 + ip_header_size + 8;
- UCHAR *reply_data = ZeroMalloc(reply_size);
- ICMP_HEADER *icmp = (ICMP_HEADER *)reply_data;
- icmp->Type = ICMP_TYPE_TIME_EXCEEDED;
- icmp->Code = ICMP_CODE_TTL_EXCEEDED_IN_TRANSIT;
- Copy(reply_data + sizeof(ICMP_HEADER) + 4, ip_header, ip_header_size);
- Copy(reply_data + sizeof(ICMP_HEADER) + 4 + ip_header_size, icmp_data, MIN(icmp_size, 8));
- icmp->Checksum = IpChecksum(icmp, reply_size);
- SendIp(v, src_ip, v->HostIP, IP_PROTO_ICMPV4, reply_data, reply_size);
- Free(reply_data);
- return;
- }
- src_port = Endian16(old_icmp_echo->Identifier);
- // Search whether there is an existing session
- NnSetNat(&tt, NAT_ICMP, src_ip, src_port, 0, 0, 0, 0);
- e = SearchHash(t->NatTableForSend, &tt);
- if (e == NULL)
- {
- // Create a new session because there is no existing one
- UINT public_port;
- if (CanCreateNewNatEntry(v) == false)
- {
- // Can not make any more
- return;
- }
- NnDeleteOldestNatSessionIfNecessary(t, src_ip, NAT_ICMP);
- // Get a free port
- public_port = NnMapNewPublicPort(t, NAT_ICMP, 0, 0, t->PublicIP);
- if (public_port == 0)
- {
- // There are no free ports
- return;
- }
- e = ZeroMalloc(sizeof(NATIVE_NAT_ENTRY));
- e->Status = NAT_TCP_ESTABLISHED;
- e->HashCodeForSend = INFINITE;
- e->HashCodeForRecv = INFINITE;
- e->Id = Inc(v->Counter);
- e->Protocol = NAT_ICMP;
- e->SrcIp = src_ip;
- e->SrcPort = src_port;
- e->DestIp = 0;
- e->DestPort = 0;
- e->PublicIp = t->PublicIP;
- e->PublicPort = public_port;
- e->CreatedTime = v->Now;
- e->LastCommTime = v->Now;
- // Add to the list
- AddHash(t->NatTableForSend, e);
- AddHash(t->NatTableForRecv, e);
- // Log
- if (true)
- {
- IP ip1, ip2;
- char s1[MAX_SIZE], s2[MAX_SIZE];
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- IPToStr(s1, 0, &ip1);
- IPToStr(s2, 0, &ip2);
- Debug("ICMP Session %u: %s:0x%x -> %s:0x%x\n", e->Id, s1, src_port, s2, public_port);
- }
- }
- // Rebuild the ICMP header
- icmp = ZeroMalloc(sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size);
- icmp->Code = old_icmp_header->Code;
- icmp->Type = old_icmp_header->Type;
- icmp->Checksum = 0;
- echo = (ICMP_ECHO *)(((UCHAR *)icmp) + sizeof(ICMP_HEADER));
- echo->SeqNo = old_icmp_echo->SeqNo;
- echo->Identifier = Endian16(e->PublicPort);
- Copy(((UCHAR *)icmp) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO), payload_data, payload_size);
- icmp->Checksum = IpChecksum(icmp, sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size);
- e->TotalSent += (UINT64)payload_size;
- e->LastCommTime = v->Now;
- // Send to the Internet
- NnIpSendForInternet(t, IP_PROTO_ICMPV4, ttl - 1, e->PublicIp, dest_ip, icmp, sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size, max_l3_size);
- Free(icmp);
- }
- // Communication of UDP towards the Internet
- void NnUdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, UINT max_l3_size)
- {
- NATIVE_NAT_ENTRY tt;
- NATIVE_NAT_ENTRY *e;
- NATIVE_NAT *t;
- UDP_HEADER *udp;
- // Validate arguments
- if (NnIsActive(v) == false || data == NULL)
- {
- return;
- }
- t = v->NativeNat;
- // Search whether there is an existing session
- NnSetNat(&tt, NAT_UDP, src_ip, src_port, 0, 0, 0, 0);
- e = SearchHash(t->NatTableForSend, &tt);
- if (e == NULL)
- {
- // Create a new session because there is no existing one
- UINT public_port;
- if (CanCreateNewNatEntry(v) == false)
- {
- // Can not make any more
- return;
- }
- NnDeleteOldestNatSessionIfNecessary(t, src_ip, NAT_UDP);
- // Get a free port
- public_port = NnMapNewPublicPort(t, NAT_UDP, 0, 0, t->PublicIP);
- if (public_port == 0)
- {
- // There are no free ports
- return;
- }
- e = ZeroMalloc(sizeof(NATIVE_NAT_ENTRY));
- e->Status = NAT_TCP_ESTABLISHED;
- e->HashCodeForSend = INFINITE;
- e->HashCodeForRecv = INFINITE;
- e->Id = Inc(v->Counter);
- e->Protocol = NAT_UDP;
- e->SrcIp = src_ip;
- e->SrcPort = src_port;
- e->DestIp = 0;
- e->DestPort = 0;
- e->PublicIp = t->PublicIP;
- e->PublicPort = public_port;
- e->CreatedTime = v->Now;
- e->LastCommTime = v->Now;
- // Add to the list
- AddHash(t->NatTableForSend, e);
- AddHash(t->NatTableForRecv, e);
- // Log
- if (true)
- {
- IP ip1, ip2;
- char s1[MAX_SIZE], s2[MAX_SIZE];
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- IPToStr(s1, 0, &ip1);
- IPToStr(s2, 0, &ip2);
- NLog(v, "LH_NAT_UDP_CREATED", e->Id, s1, src_port, s2, dest_port);
- }
- }
- // Rebuild the UDP header
- udp = ZeroMalloc(sizeof(UDP_HEADER) + size);
- udp->SrcPort = Endian16(e->PublicPort);
- udp->DstPort = Endian16(dest_port);
- udp->PacketLength = Endian16((USHORT)sizeof(UDP_HEADER) + size);
- Copy(((UCHAR *)udp) + sizeof(UDP_HEADER), data, size);
- udp->Checksum = CalcChecksumForIPv4(e->PublicIp, dest_ip, IP_PROTO_UDP, udp, sizeof(UDP_HEADER) + size, 0);
- e->TotalSent += (UINT64)size;
- e->LastCommTime = v->Now;
- // Send to the Internet
- NnIpSendForInternet(t, IP_PROTO_UDP, 127, e->PublicIp, dest_ip, udp, sizeof(UDP_HEADER) + size, max_l3_size);
- Free(udp);
- }
- // Communication of TCP towards the Internet
- void NnTcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *old_tcp, void *data, UINT size, UINT max_l3_size)
- {
- NATIVE_NAT_ENTRY tt;
- NATIVE_NAT_ENTRY *e;
- NATIVE_NAT *t;
- UINT tcp_header_size;
- TCP_HEADER *tcp;
- // Validate arguments
- if (NnIsActive(v) == false || old_tcp == NULL || data == NULL)
- {
- return;
- }
- t = v->NativeNat;
- // Search whether there is an existing session
- NnSetNat(&tt, NAT_TCP, src_ip, src_port, dest_ip, dest_port, 0, 0);
- e = SearchHash(t->NatTableForSend, &tt);
- if (e == NULL)
- {
- // Create a new session because there is no existing one
- UINT public_port;
- if (old_tcp->Flag != TCP_SYN)
- {
- // If there is no existing session, pass through only for SYN packet
- return;
- }
- if (CanCreateNewNatEntry(v) == false)
- {
- // Can not make any more
- return;
- }
- NnDeleteOldestNatSessionIfNecessary(t, src_ip, NAT_TCP);
- // Get a free port
- public_port = NnMapNewPublicPort(t, NAT_TCP, dest_ip, dest_port, t->PublicIP);
- if (public_port == 0)
- {
- // There are no free ports
- return;
- }
- e = ZeroMalloc(sizeof(NATIVE_NAT_ENTRY));
- e->HashCodeForSend = INFINITE;
- e->HashCodeForRecv = INFINITE;
- e->Id = Inc(v->Counter);
- e->Status = NAT_TCP_CONNECTING;
- e->Protocol = NAT_TCP;
- e->SrcIp = src_ip;
- e->SrcPort = src_port;
- e->DestIp = dest_ip;
- e->DestPort = dest_port;
- e->PublicIp = t->PublicIP;
- e->PublicPort = public_port;
- e->CreatedTime = v->Now;
- e->LastCommTime = v->Now;
- // Add to the list
- AddHash(t->NatTableForSend, e);
- AddHash(t->NatTableForRecv, e);
- // Log
- if (true)
- {
- IP ip1, ip2;
- char s1[MAX_SIZE], s2[MAX_SIZE];
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- IPToStr(s1, 0, &ip1);
- IPToStr(s2, 0, &ip2);
- NLog(v, "LH_NAT_TCP_CREATED", e->Id, s1, src_port, s2, dest_port);
- }
- }
- // Update the last communication time
- e->LastCommTime = v->Now;
- e->TotalSent += (UINT64)size;
- tcp_header_size = TCP_GET_HEADER_SIZE(old_tcp) * 4;
- // Create a new TCP packet
- tcp = ZeroMalloc(tcp_header_size + size);
- // Copy the old TCP header
- Copy(tcp, old_tcp, tcp_header_size);
- if (tcp->Flag & TCP_RST || tcp->Flag & TCP_FIN)
- {
- // Disconnect
- e->Status = NAT_TCP_WAIT_DISCONNECT;
- }
- // Rewrite the TCP header
- tcp->Checksum = 0;
- tcp->SrcPort = Endian16(e->PublicPort);
- e->LastSeq = Endian32(tcp->SeqNumber);
- e->LastAck = Endian32(tcp->AckNumber);
- // Payload
- Copy(((UCHAR *)tcp) + tcp_header_size, data, size);
- // Checksum calculation
- tcp->Checksum = CalcChecksumForIPv4(e->PublicIp, dest_ip, IP_PROTO_TCP, tcp, tcp_header_size + size, 0);
- // Send to the Internet
- NnIpSendForInternet(t, IP_PROTO_TCP, 127, e->PublicIp, dest_ip, tcp, tcp_header_size + size, max_l3_size);
- Free(tcp);
- }
- // Assign a new public-side port
- UINT NnMapNewPublicPort(NATIVE_NAT *t, UINT protocol, UINT dest_ip, UINT dest_port, UINT public_ip)
- {
- UINT i;
- UINT base_port;
- // Validate arguments
- if (t == NULL)
- {
- return 0;
- }
- base_port = Rand32() % (65500 - 1025) + 1025;
- for (i = 0;i < (65500 - 1025);i++)
- {
- UINT port;
- NATIVE_NAT_ENTRY tt;
- NATIVE_NAT *e;
- port = base_port + i;
- if (port > 65500)
- {
- port = port - 65500 + 1025;
- }
- // Is this port vacant?
- NnSetNat(&tt, protocol, 0, 0, dest_ip, dest_port, public_ip, port);
- e = SearchHash(t->NatTableForRecv, &tt);
- if (e == NULL)
- {
- // Free port is found
- return port;
- }
- }
- return 0;
- }
- // Examine whether the native NAT is available
- bool NnIsActive(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return false;
- }
- if (v->NativeNat == NULL)
- {
- return false;
- }
- if (v->NativeNat->PublicIP == 0)
- {
- return false;
- }
- return v->NativeNat->Active;
- }
- // Native NAT main loop
- void NnMainLoop(NATIVE_NAT *t, NATIVE_STACK *a)
- {
- IPC *ipc;
- TUBE *tubes[3];
- UINT num_tubes = 0;
- UINT64 next_poll_tick = 0;
- INTERRUPT_MANAGER *interrupt;
- USHORT dns_src_port = 0;
- USHORT dns_tran_id = 0;
- USHORT tcp_src_port = 0;
- UINT tcp_seq = 0;
- IP yahoo_ip;
- bool wait_for_dns = false;
- UINT64 tcp_last_recv_tick = 0;
- UINT dhcp_renew_interval;
- UINT64 next_dhcp_renew_tick = 0;
- // Validate arguments
- if (t == NULL || a == NULL)
- {
- return;
- }
- dhcp_renew_interval = a->CurrentDhcpOptionList.LeaseTime;
- if (dhcp_renew_interval == 0)
- {
- dhcp_renew_interval = IPC_DHCP_DEFAULT_LEASE;
- }
- dhcp_renew_interval = MAX(dhcp_renew_interval, IPC_DHCP_MIN_LEASE) / 2;
- interrupt = NewInterruptManager();
- ipc = a->Ipc;
- tubes[num_tubes++] = ipc->Sock->RecvTube;
- tubes[num_tubes++] = ipc->Sock->SendTube;
- tubes[num_tubes++] = t->HaltTube;
- Zero(&yahoo_ip, sizeof(yahoo_ip));
- next_poll_tick = Tick64() + (UINT64)NN_POLL_CONNECTIVITY_INTERVAL;
- AddInterrupt(interrupt, next_poll_tick);
- tcp_last_recv_tick = Tick64();
- next_dhcp_renew_tick = Tick64() + (UINT64)dhcp_renew_interval;
- AddInterrupt(interrupt, next_dhcp_renew_tick);
- while (t->Halt == false && t->v->UseNat && ((t->v->HubOption == NULL) || (t->v->HubOption->DisableKernelModeSecureNAT == false)))
- {
- UINT64 now = Tick64();
- bool call_cancel = false;
- bool state_changed = false;
- UINT wait_interval;
- IPCFlushArpTable(ipc);
- call_cancel = false;
- LABEL_RESTART:
- state_changed = false;
- if (next_poll_tick == 0 || next_poll_tick <= now)
- {
- BUF *dns_query;
- dns_src_port = NnGenSrcPort();
- dns_tran_id = Rand16();
- // Start a connectivity check periodically
- dns_query = NnBuildIpPacket(NnBuildUdpPacket(NnBuildDnsQueryPacket(NN_CHECK_HOSTNAME, dns_tran_id),
- IPToUINT(&ipc->ClientIPAddress), dns_src_port, IPToUINT(&a->DnsServerIP), 53),
- IPToUINT(&ipc->ClientIPAddress), IPToUINT(&a->DnsServerIP), IP_PROTO_UDP, 0);
- IPCSendIPv4(ipc, dns_query->Buf, dns_query->Size);
- wait_for_dns = true;
- FreeBuf(dns_query);
- next_poll_tick = now + (UINT64)NN_POLL_CONNECTIVITY_INTERVAL;
- AddInterrupt(interrupt, next_poll_tick);
- }
- if (next_dhcp_renew_tick == 0 || next_dhcp_renew_tick <= now)
- {
- IP ip;
- UINTToIP(&ip, a->CurrentDhcpOptionList.ServerAddress);
- IPCDhcpRenewIP(ipc, &ip);
- next_dhcp_renew_tick = now + (UINT64)dhcp_renew_interval;
- AddInterrupt(interrupt, next_dhcp_renew_tick);
- }
- // Send an IP packet to IPC
- LockQueue(t->SendQueue);
- {
- while (true)
- {
- BLOCK *b = GetNext(t->SendQueue);
- if (b == NULL)
- {
- break;
- }
- IPCSendIPv4(ipc, b->Buf, b->Size);
- state_changed = true;
- FreeBlock(b);
- }
- }
- UnlockQueue(t->SendQueue);
- // Happy processing
- IPCProcessL3Events(ipc);
- LockQueue(t->RecvQueue);
- {
- while (true)
- {
- // Receive an IP packet from IPC
- BLOCK *b = IPCRecvIPv4(ipc);
- PKT *pkt;
- if (b == NULL)
- {
- // Can not receive any more
- break;
- }
- // Parse the packet
- pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
- FreeBlock(b);
- if (pkt != NULL)
- {
- bool no_store = false;
- // Read the contents of the packet first, to determine whether it is a response for the connectivity test packet
- if (wait_for_dns)
- {
- if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_UDP &&
- pkt->L3.IPv4Header->SrcIP == IPToUINT(&a->DnsServerIP) &&
- pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
- pkt->L4.UDPHeader->SrcPort == Endian16(53) && pkt->L4.UDPHeader->DstPort == Endian16(dns_src_port))
- {
- DNSV4_HEADER *dns_header = (DNSV4_HEADER *)pkt->Payload;
- if (pkt->PayloadSize >= sizeof(DNSV4_HEADER))
- {
- if (dns_header->TransactionId == Endian16(dns_tran_id))
- {
- IP ret_ip;
- if (NnParseDnsResponsePacket(pkt->Payload, pkt->PayloadSize, &ret_ip))
- {
- BUF *tcp_query;
- Copy(&yahoo_ip, &ret_ip, sizeof(IP));
- //SetIP(&yahoo_ip, 192, 168, 2, 32);
- // DNS response has been received
- no_store = true;
- tcp_src_port = NnGenSrcPort();
- // Generate a TCP connection attempt packet
- tcp_seq = Rand32();
- tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), tcp_src_port,
- IPToUINT(&yahoo_ip), 80, tcp_seq, 0, TCP_SYN, 8192, 1414),
- IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
- IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
- FreeBuf(tcp_query);
- wait_for_dns = false;
- }
- }
- }
- }
- }
- if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_TCP &&
- pkt->L3.IPv4Header->SrcIP == IPToUINT(&yahoo_ip) &&
- pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
- pkt->L4.TCPHeader->SrcPort == Endian16(80) && pkt->L4.TCPHeader->DstPort == Endian16(tcp_src_port))
- {
- TCP_HEADER *tcp_header = (TCP_HEADER *)pkt->L4.TCPHeader;
- if ((tcp_header->Flag & TCP_SYN) && (tcp_header->Flag & TCP_ACK))
- {
- // There was a TCP response
- BUF *tcp_query;
- UINT recv_seq = Endian32(tcp_header->SeqNumber) + 1;
- no_store = true;
- // Send a RST
- tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), tcp_src_port,
- IPToUINT(&yahoo_ip), 80, tcp_seq + 1, recv_seq, TCP_RST | TCP_ACK, 8192, 0),
- IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
- IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
- FreeBuf(tcp_query);
- tcp_last_recv_tick = now;
- }
- }
- if (t->RecvQueue->num_item > NN_MAX_QUEUE_LENGTH)
- {
- no_store = true;
- }
- if (no_store == false)
- {
- // Put in the queue
- InsertQueue(t->RecvQueue, pkt);
- call_cancel = true;
- state_changed = true;
- }
- else
- {
- // Release the packet
- FreePacketWithData(pkt);
- }
- }
- }
- }
- UnlockQueue(t->RecvQueue);
- if (state_changed)
- {
- goto LABEL_RESTART;
- }
- if (call_cancel)
- {
- CANCEL *c = NULL;
- Lock(t->CancelLock);
- {
- c = t->Cancel;
- AddRef(c->ref);
- }
- Unlock(t->CancelLock);
- if (c != NULL)
- {
- Cancel(c);
- ReleaseCancel(c);
- }
- }
- if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false)
- {
- // Disconnected
- break;
- }
- if ((tcp_last_recv_tick + (UINT64)NN_POLL_CONNECTIVITY_TIMEOUT) < now)
- {
- // Connectivity test has timed out because a certain period of time has elapsed
- Debug("NN_POLL_CONNECTIVITY_TIMEOUT\n");
- break;
- }
- wait_interval = GetNextIntervalForInterrupt(interrupt);
- wait_interval = MIN(wait_interval, 1234);
- if (wait_interval != 0)
- {
- WaitForTubes(tubes, num_tubes, wait_interval);
- }
- }
- FreeInterruptManager(interrupt);
- }
- // Build an IP packet
- BUF *NnBuildIpPacket(BUF *payload, UINT src_ip, UINT dst_ip, UCHAR protocol, UCHAR ttl)
- {
- BUF *ret = NewBuf();
- IPV4_HEADER h;
- if (ttl == 0)
- {
- ttl = 127;
- }
- // IP header
- Zero(&h, sizeof(h));
- IPV4_SET_VERSION(&h, 4);
- IPV4_SET_HEADER_LEN(&h, sizeof(IPV4_HEADER) / 4);
- h.TotalLength = Endian16((USHORT)sizeof(IPV4_HEADER) + payload->Size);
- h.Identification = Rand16();
- h.TimeToLive = ttl;
- h.Protocol = protocol;
- h.SrcIP = src_ip;
- h.DstIP = dst_ip;
- h.Checksum = IpChecksum(&h, sizeof(h));
- WriteBuf(ret, &h, sizeof(h));
- WriteBufBuf(ret, payload);
- SeekBufToBegin(ret);
- FreeBuf(payload);
- return ret;
- }
- // Build an UDP packet
- BUF *NnBuildUdpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port)
- {
- BUF *ret = NewBuf();
- BUF *phbuf = NewBuf();
- UDPV4_PSEUDO_HEADER ph;
- UDP_HEADER h;
- // UDP pseudo header
- Zero(&ph, sizeof(ph));
- ph.SrcIP = src_ip;
- ph.DstIP = dst_ip;
- ph.SrcPort = Endian16(src_port);
- ph.DstPort = Endian16(dst_port);
- ph.Protocol = IP_PROTO_UDP;
- ph.PacketLength1 = ph.PacketLength2 = Endian16(payload->Size + (USHORT)sizeof(UDP_HEADER));
- WriteBuf(phbuf, &ph, sizeof(ph));
- WriteBufBuf(phbuf, payload);
- // UDP header
- Zero(&h, sizeof(h));
- h.SrcPort = Endian16(src_port);
- h.DstPort = Endian16(dst_port);
- h.PacketLength = Endian16(payload->Size + (USHORT)sizeof(UDP_HEADER));
- h.Checksum = IpChecksum(phbuf->Buf, phbuf->Size);
- WriteBuf(ret, &h, sizeof(h));
- WriteBuf(ret, payload->Buf, payload->Size);
- SeekBufToBegin(ret);
- FreeBuf(payload);
- FreeBuf(phbuf);
- return ret;
- }
- // Build a TCP packet
- BUF *NnBuildTcpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss)
- {
- BUF *ret;
- IPV4_PSEUDO_HEADER *vh;
- TCP_HEADER *tcp;
- static UCHAR tcp_mss_option[] = {0x02, 0x04, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00};
- UINT header_size = TCP_HEADER_SIZE;
- UINT total_size;
- // Memory allocation
- vh = Malloc(sizeof(IPV4_PSEUDO_HEADER) + TCP_HEADER_SIZE + payload->Size + 32);
- tcp = (TCP_HEADER *)(((UCHAR *)vh) + sizeof(IPV4_PSEUDO_HEADER));
- if (mss != 0)
- {
- USHORT *mss_size;
- mss_size = (USHORT *)(&tcp_mss_option[2]);
- *mss_size = Endian16((USHORT)mss);
- header_size += sizeof(tcp_mss_option);
- }
- total_size = header_size + payload->Size;
- // Pseudo header generation
- vh->SrcIP = src_ip;
- vh->DstIP = dst_ip;
- vh->Reserved = 0;
- vh->Protocol = IP_PROTO_TCP;
- vh->PacketLength = Endian16((USHORT)total_size);
- // TCP header generation
- tcp->SrcPort = Endian16((USHORT)src_port);
- tcp->DstPort = Endian16((USHORT)dst_port);
- tcp->SeqNumber = Endian32(seq);
- tcp->AckNumber = Endian32(ack);
- tcp->HeaderSizeAndReserved = 0;
- TCP_SET_HEADER_SIZE(tcp, (UCHAR)(header_size / 4));
- tcp->Flag = (UCHAR)flag;
- tcp->WindowSize = Endian16((USHORT)window_size);
- tcp->Checksum = 0;
- tcp->UrgentPointer = 0;
- // Copy the option values
- if (mss != 0)
- {
- Copy(((UCHAR *)tcp) + TCP_HEADER_SIZE, tcp_mss_option, sizeof(tcp_mss_option));
- }
- // Data copy
- Copy(((UCHAR *)tcp) + header_size, payload->Buf, payload->Size);
- // Checksum calculation
- tcp->Checksum = IpChecksum(vh, total_size + 12);
- ret = NewBufFromMemory(tcp, total_size);
- Free(vh);
- FreeBuf(payload);
- return ret;
- }
- // Build a DNS query packet
- BUF *NnBuildDnsQueryPacket(char *hostname, USHORT tran_id)
- {
- BUF *buf = NewBuf();
- DNSV4_HEADER header;
- Zero(&header, sizeof(header));
- header.TransactionId = Endian16(tran_id);
- header.Flag1 = 0x01;
- header.Flag2 = 0x00;
- header.NumQuery = Endian16(1);
- WriteBuf(buf, &header, sizeof(header));
- BuildDnsQueryPacket(buf, hostname, false);
- SeekBufToBegin(buf);
- return buf;
- }
- // Read a DNS record
- BUF *NnReadDnsRecord(BUF *buf, bool answer, USHORT *ret_type, USHORT *ret_class)
- {
- USHORT type;
- USHORT clas;
- UINT ttl;
- BUF *ret = NULL;
- // Validate arguments
- if (buf == NULL)
- {
- return NULL;
- }
- // Read the DNS label
- if (NnReadDnsLabel(buf) == false)
- {
- return false;
- }
- // Type and Class
- if (ReadBuf(buf, &type, sizeof(USHORT)) != sizeof(USHORT))
- {
- return false;
- }
- if (ret_type != NULL)
- {
- *ret_type = Endian16(type);
- }
- if (ReadBuf(buf, &clas, sizeof(USHORT)) != sizeof(USHORT))
- {
- return false;
- }
- if (ret_class != NULL)
- {
- *ret_class = Endian16(clas);
- }
- if (answer)
- {
- USHORT data_len;
- UCHAR *data;
- // TTL
- if (ReadBuf(buf, &ttl, sizeof(UINT)) != sizeof(UINT))
- {
- return false;
- }
- // data_len
- if (ReadBuf(buf, &data_len, sizeof(USHORT)) != sizeof(USHORT))
- {
- return false;
- }
- data_len = Endian16(data_len);
- // data
- data = Malloc(data_len);
- if (ReadBuf(buf, data, data_len) != data_len)
- {
- return false;
- }
- ret = NewBufFromMemory(data, data_len);
- Free(data);
- }
- else
- {
- ret = NewBuf();
- }
- return ret;
- }
- // Read the DNS label
- bool NnReadDnsLabel(BUF *buf)
- {
- UCHAR c;
- UCHAR tmp[256];
- // Validate arguments
- if (buf == NULL)
- {
- return false;
- }
- LABEL_START:
- if (ReadBuf(buf, &c, 1) != 1)
- {
- return false;
- }
- if (c == 0)
- {
- return true;
- }
- if (c & 0xC0)
- {
- // Compression label
- if (ReadBuf(buf, &c, 1) != 1)
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- else
- {
- // Usual label
- if (ReadBuf(buf, tmp, c) != c)
- {
- return false;
- }
- else
- {
- goto LABEL_START;
- }
- }
- }
- // Parse the DNS response packet
- bool NnParseDnsResponsePacket(UCHAR *data, UINT size, IP *ret_ip)
- {
- BUF *buf = NewBufFromMemory(data, size);
- bool ret = false;
- DNSV4_HEADER h;
- if (ReadBuf(buf, &h, sizeof(h)) == sizeof(h))
- {
- UINT num_questions = Endian16(h.NumQuery);
- UINT num_answers = Endian16(h.AnswerRRs);
- UINT i;
- for (i = 0;i < num_questions;i++)
- {
- BUF *r = NnReadDnsRecord(buf, false, NULL, NULL);
- if (r != NULL)
- {
- FreeBuf(r);
- }
- else
- {
- goto LABEL_CLEANUP;
- }
- }
- for (i = 0;i < num_answers;i++)
- {
- USHORT tp, cl;
- BUF *r = NnReadDnsRecord(buf, true, &tp, &cl);
- if (r != NULL)
- {
- if (tp == 0x0001 && cl == 0x0001 && r->Size == 4)
- {
- ret = true;
- if (ret_ip != NULL)
- {
- Zero(ret_ip, sizeof(IP));
- Copy(ret_ip->addr, r->Buf, 4);
- }
- }
- FreeBuf(r);
- }
- else
- {
- goto LABEL_CLEANUP;
- }
- }
- }
- LABEL_CLEANUP:
- FreeBuf(buf);
- return ret;
- }
- // Test the connectivity of the stack to the Internet
- bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
- {
- BUF *dns_query;
- bool ok = false;
- USHORT dns_tran_id = Rand16();
- UINT64 next_send_tick = 0;
- UINT64 giveup_time;
- IPC *ipc;
- UINT src_port = NnGenSrcPort();
- INTERRUPT_MANAGER *interrupt;
- TUBE *tubes[3];
- UINT num_tubes = 0;
- IP yahoo_ip;
- // Validate arguments
- if (a == NULL)
- {
- return false;
- }
- ipc = a->Ipc;
- interrupt = NewInterruptManager();
- tubes[num_tubes++] = ipc->Sock->RecvTube;
- tubes[num_tubes++] = ipc->Sock->SendTube;
- if (halt_tube != NULL)
- {
- tubes[num_tubes++] = halt_tube;
- }
- Zero(&yahoo_ip, sizeof(yahoo_ip));
- // Try to get an IP address of www.yahoo.com
- dns_query = NnBuildIpPacket(NnBuildUdpPacket(NnBuildDnsQueryPacket(NN_CHECK_HOSTNAME, dns_tran_id),
- IPToUINT(&ipc->ClientIPAddress), src_port, IPToUINT(&a->DnsServerIP), 53),
- IPToUINT(&ipc->ClientIPAddress), IPToUINT(&a->DnsServerIP), IP_PROTO_UDP, 0);
- giveup_time = Tick64() + NN_CHECK_CONNECTIVITY_TIMEOUT;
- AddInterrupt(interrupt, giveup_time);
- while (true)
- {
- UINT64 now = Tick64();
- IPCFlushArpTable(a->Ipc);
- if (now >= giveup_time)
- {
- break;
- }
- // Send a packet periodically
- if (next_send_tick == 0 || next_send_tick <= now)
- {
- next_send_tick = now + (UINT64)NN_CHECK_CONNECTIVITY_INTERVAL;
- AddInterrupt(interrupt, next_send_tick);
- IPCSendIPv4(ipc, dns_query->Buf, dns_query->Size);
- }
- // Happy processing
- IPCProcessL3Events(ipc);
- while (true)
- {
- // Receive a packet
- BLOCK *b = IPCRecvIPv4(ipc);
- PKT *pkt;
- if (b == NULL)
- {
- break;
- }
- // Parse the packet
- pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
- if (pkt != NULL)
- {
- if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_UDP &&
- pkt->L3.IPv4Header->SrcIP == IPToUINT(&a->DnsServerIP) &&
- pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
- pkt->L4.UDPHeader->SrcPort == Endian16(53) && pkt->L4.UDPHeader->DstPort == Endian16(src_port))
- {
- DNSV4_HEADER *dns_header = (DNSV4_HEADER *)pkt->Payload;
- if (pkt->PayloadSize >= sizeof(DNSV4_HEADER))
- {
- if (dns_header->TransactionId == Endian16(dns_tran_id))
- {
- IP ret_ip;
- if (NnParseDnsResponsePacket(pkt->Payload, pkt->PayloadSize, &ret_ip))
- {
- Copy(&yahoo_ip, &ret_ip, sizeof(IP));
- }
- }
- }
- }
- }
- FreePacketWithData(pkt);
- FreeBlock(b);
- }
- if ((halt_tube != NULL && IsTubeConnected(halt_tube) == false) ||
- IsTubeConnected(ipc->Sock->SendTube) == false || IsTubeConnected(ipc->Sock->RecvTube) == false)
- {
- // Disconnected
- break;
- }
- if (IsZeroIP(&yahoo_ip) == false)
- {
- // There is a response
- break;
- }
- // Keep the CPU waiting
- WaitForTubes(tubes, num_tubes, GetNextIntervalForInterrupt(interrupt));
- }
- FreeBuf(dns_query);
- if (IsZeroIP(&yahoo_ip) == false)
- {
- BUF *tcp_query;
- UINT seq = Rand32();
- bool tcp_get_response = false;
- UINT recv_seq = 0;
- // Since the IP address of www.yahoo.com has gotten, try to connect by TCP
- giveup_time = Tick64() + NN_CHECK_CONNECTIVITY_TIMEOUT;
- AddInterrupt(interrupt, giveup_time);
- // Generate a TCP packet
- tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), src_port,
- IPToUINT(&yahoo_ip), 80, seq, 0, TCP_SYN, 8192, 1414),
- IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
- Debug("Test TCP to %r\n", &yahoo_ip);
- next_send_tick = 0;
- while (true)
- {
- UINT64 now = Tick64();
- IPCFlushArpTable(a->Ipc);
- if (now >= giveup_time)
- {
- break;
- }
- // Send the packet periodically
- if (next_send_tick == 0 || next_send_tick <= now)
- {
- next_send_tick = now + (UINT64)NN_CHECK_CONNECTIVITY_INTERVAL;
- AddInterrupt(interrupt, next_send_tick);
- IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
- }
- // Happy procedure
- IPCProcessL3Events(ipc);
- while (true)
- {
- // Receive a packet
- BLOCK *b = IPCRecvIPv4(ipc);
- PKT *pkt;
- if (b == NULL)
- {
- break;
- }
- // Parse the packet
- pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
- if (pkt != NULL)
- {
- if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_TCP &&
- pkt->L3.IPv4Header->SrcIP == IPToUINT(&yahoo_ip) &&
- pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
- pkt->L4.TCPHeader->SrcPort == Endian16(80) && pkt->L4.TCPHeader->DstPort == Endian16(src_port))
- {
- TCP_HEADER *tcp_header = (TCP_HEADER *)pkt->L4.TCPHeader;
- if ((tcp_header->Flag & TCP_SYN) && (tcp_header->Flag & TCP_ACK))
- {
- // There was a TCP response
- tcp_get_response = true;
- recv_seq = Endian32(tcp_header->SeqNumber);
- }
- }
- }
- FreePacketWithData(pkt);
- FreeBlock(b);
- }
- if ((halt_tube != NULL && IsTubeConnected(halt_tube) == false) ||
- IsTubeConnected(ipc->Sock->SendTube) == false || IsTubeConnected(ipc->Sock->RecvTube) == false)
- {
- // Disconnected
- break;
- }
- if (tcp_get_response)
- {
- WHERE;
- break;
- }
- // Keep the CPU waiting
- WaitForTubes(tubes, num_tubes, GetNextIntervalForInterrupt(interrupt));
- }
- FreeBuf(tcp_query);
- // Send a RST
- if (recv_seq != 0)
- {
- recv_seq++;
- }
- tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), src_port,
- IPToUINT(&yahoo_ip), 80, seq + 1, recv_seq, TCP_RST | TCP_ACK, 8192, 0),
- IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
- IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
- FreeBuf(tcp_query);
- SleepThread(100);
- if (tcp_get_response)
- {
- ok = true;
- }
- }
- FreeInterruptManager(interrupt);
- return ok;
- }
- // Generate source port number by a random number
- UINT NnGenSrcPort()
- {
- return 1025 + Rand32() % (65500 - 1025);
- }
- // Get a next good interface for the native NAT
- NATIVE_STACK *NnGetNextInterface(NATIVE_NAT *t)
- {
- NATIVE_STACK *ret = NULL;
- UINT current_hash;
- TOKEN_LIST *device_list;
- UINT i;
- char tmp[MAX_SIZE];
- char *dev_name;
- UINT current_ip_hash;
- // Validate arguments
- if (t == NULL)
- {
- return NULL;
- }
- t->NextWaitTimeForRetry = NN_NEXT_WAIT_TIME_FOR_DEVICE_ENUM * MIN((t->FailedCount + 1), NN_NEXT_WAIT_TIME_MAX_FAIL_COUNT);
- // Get the device list
- device_list = GetEthList();
- if (device_list == NULL || device_list->NumTokens == 0)
- {
- // Device list acquisition failure (Or no device acquired as a result)
- FreeToken(device_list);
- t->FailedCount++;
- return NULL;
- }
- current_hash = GetEthDeviceHash();
- current_ip_hash = GetHostIPAddressHash32();
- if (t->LastInterfaceDeviceHash != current_hash || t->LastHostAddressHash != current_ip_hash)
- {
- // Device list is altered from the previous search
- t->LastInterfaceIndex = INFINITE;
- t->FailedCount = 0;
- }
- t->LastInterfaceDeviceHash = current_hash;
- t->LastHostAddressHash = current_ip_hash;
- if (t->LastInterfaceIndex == INFINITE)
- {
- i = 0;
- }
- else
- {
- i = t->LastInterfaceIndex + 1;
- if (i >= device_list->NumTokens)
- {
- i = 0;
- }
- }
- if ((i + 1) == device_list->NumTokens)
- {
- // Searched to the end
- t->LastInterfaceIndex = INFINITE;
- // Increase the number of search failures by one
- t->FailedCount++;
- }
- else
- {
- // It is not the end yet
- t->LastInterfaceIndex = i;
- t->NextWaitTimeForRetry = 0;
- }
- dev_name = device_list->Token[i];
- if (IsInLinesFile(NN_NO_NATIVE_NAT_FILENAME, dev_name, true) == false)
- {
- // Try to open the device
- BinToStr(tmp, sizeof(tmp), t->v->MacAddress, 6);
- ret = NewNativeStack(NULL, dev_name, tmp);
- if (ret != NULL)
- {
- // Test whether an IP address can be obtained from a DHCP server
- DHCP_OPTION_LIST opt;
- Copy(t->CurrentMacAddress, ret->Ipc->MacAddress, 6);
- Zero(&opt, sizeof(opt));
- BinToStr(tmp, sizeof(tmp), ret->MacAddress, 6);
- Format(ret->Ipc->ClientHostname, sizeof(ret->Ipc->ClientHostname), NN_HOSTNAME_FORMAT, tmp);
- StrLower(ret->Ipc->ClientHostname);
- Debug("IPCDhcpAllocateIP for %s\n", ret->DeviceName);
- if (IPCDhcpAllocateIP(ret->Ipc, &opt, t->HaltTube2))
- {
- char client_ip[64];
- char dhcp_ip[64];
- char client_mask[64];
- char gateway_ip[64];
- IP ip;
- IP subnet;
- IP gw;
- IPToStr32(client_ip, sizeof(client_ip), opt.ClientAddress);
- IPToStr32(client_mask, sizeof(client_mask), opt.SubnetMask);
- IPToStr32(dhcp_ip, sizeof(dhcp_ip), opt.ServerAddress);
- IPToStr32(gateway_ip, sizeof(gateway_ip), opt.Gateway);
- Debug("DHCP: client_ip=%s, client_mask=%s, dhcp_ip=%s, gateway_ip=%s\n",
- client_ip, client_mask, dhcp_ip, gateway_ip);
- Copy(&ret->CurrentDhcpOptionList, &opt, sizeof(DHCP_OPTION_LIST));
- // IP parameter settings
- UINTToIP(&ip, opt.ClientAddress);
- UINTToIP(&subnet, opt.SubnetMask);
- UINTToIP(&gw, opt.Gateway);
- IPCSetIPv4Parameters(ret->Ipc, &ip, &subnet, &gw, &opt.ClasslessRoute);
- // Determine the DNS server to use
- UINTToIP(&ret->DnsServerIP, opt.DnsServer);
- if (IsZeroIP(&ret->DnsServerIP))
- {
- // Use 8.8.8.8 instead If the DNS is not assigned from the DHCP server
- SetIP(&ret->DnsServerIP, 8, 8, 8, 8);
- }
- // Connectivity test
- // (always fail if the default gateway is not set)
- if (opt.Gateway != 0 &&
- NnTestConnectivity(ret, t->HaltTube2))
- {
- // Reset the number of search failures
- t->FailedCount = 0;
- Debug("Connectivity OK.\n");
- }
- else
- {
- Debug("Connectivity Failed.\n");
- FreeNativeStack(ret);
- ret = NULL;
- }
- }
- else
- {
- Debug("DHCP Failed.\n");
- FreeNativeStack(ret);
- ret = NULL;
- Zero(t->CurrentMacAddress, sizeof(t->CurrentMacAddress));
- }
- }
- }
- FreeToken(device_list);
- return ret;
- }
- // Native NAT thread
- void NativeNatThread(THREAD *thread, void *param)
- {
- NATIVE_NAT *t = (NATIVE_NAT *)param;
- void *wait_handle = InitWaitUntilHostIPAddressChanged();
- // Validate arguments
- if (thread == NULL || param == NULL)
- {
- return;
- }
- while (t->Halt == false)
- {
- NATIVE_STACK *a;
- while (t->v->UseNat == false || (t->v->HubOption != NULL && t->v->HubOption->DisableKernelModeSecureNAT))
- {
- if (t->Halt)
- {
- break;
- }
- // If the NAT is disabled, wait until it becomes enabled
- Wait(t->HaltEvent, 1234);
- }
- if (t->Halt)
- {
- break;
- }
- // Get a next good native NAT stack
- Debug("NnGetNextInterface Start.\n");
- NnClearQueue(t);
- a = NnGetNextInterface(t);
- if (a != NULL)
- {
- char macstr[64];
- // Acquisition success
- Debug("NnGetNextInterface Ok: %s\n", a->DeviceName);
- Lock(t->Lock);
- {
- if (a->Sock1 != NULL)
- {
- t->HaltTube = a->Sock2->RecvTube;
- if (t->HaltTube != NULL)
- {
- AddRef(t->HaltTube->Ref);
- }
- }
- }
- Unlock(t->Lock);
- NnClearQueue(t);
- t->PublicIP = IPToUINT(&a->Ipc->ClientIPAddress);
- t->Active = true;
- Debug("NnMainLoop Start.\n");
- MacToStr(macstr, sizeof(macstr), a->Ipc->MacAddress);
- NLog(t->v, "LH_KERNEL_MODE_START", a->DeviceName,
- &a->Ipc->ClientIPAddress, &a->Ipc->SubnetMask, &a->Ipc->DefaultGateway, &a->Ipc->BroadcastAddress,
- macstr, &a->CurrentDhcpOptionList.ServerAddress, &a->DnsServerIP);
- NnMainLoop(t, a);
- Debug("NnMainLoop End.\n");
- t->Active = false;
- t->PublicIP = 0;
- NnClearQueue(t);
- // Close the stack
- Lock(t->Lock);
- {
- if (t->HaltTube != NULL)
- {
- ReleaseTube(t->HaltTube);
- t->HaltTube = NULL;
- }
- }
- Unlock(t->Lock);
- FreeNativeStack(a);
- Zero(t->CurrentMacAddress, 6);
- }
- else
- {
- Debug("NnGetNextInterface Failed.\n");
- }
- // Wait for a certain period of time
- if (t->NextWaitTimeForRetry != 0)
- {
- WaitUntilHostIPAddressChanged(wait_handle, t->HaltEvent, t->NextWaitTimeForRetry, 1000);
- }
- }
- FreeWaitUntilHostIPAddressChanged(wait_handle);
- }
- // Erase the contents of the queue for transmission and reception
- void NnClearQueue(NATIVE_NAT *t)
- {
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- LockQueue(t->SendQueue);
- {
- while (true)
- {
- BLOCK *b = GetNext(t->SendQueue);
- if (b == NULL)
- {
- break;
- }
- FreeBlock(b);
- }
- }
- UnlockQueue(t->SendQueue);
- LockQueue(t->RecvQueue);
- {
- while (true)
- {
- PKT *p = GetNext(t->RecvQueue);
- if (p == NULL)
- {
- break;
- }
- FreePacketWithData(p);
- }
- }
- UnlockQueue(t->RecvQueue);
- }
- // Structure setting function to search for native NAT
- void NnSetNat(NATIVE_NAT_ENTRY *e, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT pub_ip, UINT pub_port)
- {
- // Validate arguments
- if (e == NULL)
- {
- return;
- }
- Zero(e, sizeof(NATIVE_NAT_ENTRY));
- e->Protocol = protocol;
- e->SrcIp = src_ip;
- e->SrcPort = src_port;
- e->DestIp = dest_ip;
- e->DestPort = dest_port;
- e->PublicIp = pub_ip;
- e->PublicPort = pub_port;
- e->HashCodeForSend = e->HashCodeForRecv = INFINITE;
- }
- // Get the hash code of the native NAT table (receiving direction)
- UINT GetHashNativeNatTableForRecv(void *p)
- {
- UINT r;
- NATIVE_NAT_ENTRY *e = (NATIVE_NAT_ENTRY *)p;
- if (e == NULL)
- {
- return 0;
- }
- if (e->HashCodeForRecv != INFINITE)
- {
- return e->HashCodeForRecv;
- }
- r = 0;
- r += e->Protocol;
- r += e->PublicIp;
- r += e->PublicPort;
- if (e->Protocol == NAT_TCP)
- {
- r += e->DestIp;
- r += e->DestPort;
- }
- e->HashCodeForRecv = r;
- return r;
- }
- // Comparison function of native NAT table (receiving direction)
- int CmpNativeNatTableForRecv(void *p1, void *p2)
- {
- int r;
- NATIVE_NAT_ENTRY *e1, *e2;
- if (p1 == NULL || p2 == NULL)
- {
- return 0;
- }
- e1 = *(NATIVE_NAT_ENTRY **)p1;
- e2 = *(NATIVE_NAT_ENTRY **)p2;
- if (e1 == NULL || e2 == NULL)
- {
- return 0;
- }
- r = COMPARE_RET(e1->Protocol, e2->Protocol);
- if (r != 0)
- {
- return r;
- }
- r = COMPARE_RET(e1->PublicIp, e2->PublicIp);
- if (r != 0)
- {
- return r;
- }
- r = COMPARE_RET(e1->PublicPort, e2->PublicPort);
- if (r != 0)
- {
- return r;
- }
- if (e1->Protocol == NAT_TCP)
- {
- r = COMPARE_RET(e1->DestIp, e2->DestIp);
- if (r != 0)
- {
- return r;
- }
- r = COMPARE_RET(e1->DestPort, e2->DestPort);
- if (r != 0)
- {
- return r;
- }
- }
- return 0;
- }
- // Get the hash code of the native NAT table (transmit direction)
- UINT GetHashNativeNatTableForSend(void *p)
- {
- UINT r;
- NATIVE_NAT_ENTRY *e = (NATIVE_NAT_ENTRY *)p;
- if (e == NULL)
- {
- return 0;
- }
- if (e->HashCodeForSend != INFINITE)
- {
- return e->HashCodeForSend;
- }
- r = 0;
- r += e->Protocol;
- r += e->SrcIp;
- r += e->SrcPort;
- if (e->Protocol == NAT_TCP)
- {
- r += e->DestIp;
- r += e->DestPort;
- }
- e->HashCodeForSend = r;
- return r;
- }
- // Comparison function of native NAT table (transmit direction)
- int CmpNativeNatTableForSend(void *p1, void *p2)
- {
- int r;
- NATIVE_NAT_ENTRY *e1, *e2;
- if (p1 == NULL || p2 == NULL)
- {
- return 0;
- }
- e1 = *(NATIVE_NAT_ENTRY **)p1;
- e2 = *(NATIVE_NAT_ENTRY **)p2;
- if (e1 == NULL || e2 == NULL)
- {
- return 0;
- }
- r = COMPARE_RET(e1->Protocol, e2->Protocol);
- if (r != 0)
- {
- return r;
- }
- r = COMPARE_RET(e1->SrcIp, e2->SrcIp);
- if (r != 0)
- {
- return r;
- }
- r = COMPARE_RET(e1->SrcPort, e2->SrcPort);
- if (r != 0)
- {
- return r;
- }
- if (e1->Protocol == NAT_TCP)
- {
- r = COMPARE_RET(e1->DestIp, e2->DestIp);
- if (r != 0)
- {
- return r;
- }
- r = COMPARE_RET(e1->DestPort, e2->DestPort);
- if (r != 0)
- {
- return r;
- }
- }
- return 0;
- }
- // Start the native NAT
- NATIVE_NAT *NewNativeNat(VH *v)
- {
- NATIVE_NAT *t;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- t = ZeroMalloc(sizeof(NATIVE_NAT));
- t->v = v;
- t->Cancel = v->Cancel;
- AddRef(t->Cancel->ref);
- // Data structure initialization
- t->LastInterfaceIndex = INFINITE;
- t->SendQueue = NewQueue();
- t->RecvQueue = NewQueue();
- NnInitIpCombineList(t);
- t->Lock = NewLock();
- t->CancelLock = NewLock();
- t->HaltEvent = NewEvent();
- NewTubePair(&t->HaltTube2, &t->HaltTube3, 0);
- // Create a NAT table
- t->NatTableForSend = NewHashList(GetHashNativeNatTableForSend, CmpNativeNatTableForSend, 11, true);
- t->NatTableForRecv = NewHashList(GetHashNativeNatTableForRecv, CmpNativeNatTableForRecv, 11, true);
- t->Thread = NewThread(NativeNatThread, t);
- return t;
- }
- // Stop the native NAT
- void FreeNativeNat(NATIVE_NAT *t)
- {
- TUBE *tube;
- UINT i;
- // Validate arguments
- if (t == NULL)
- {
- return;
- }
- t->Halt = true;
- Lock(t->Lock);
- {
- tube = t->HaltTube;
- if (tube != NULL)
- {
- AddRef(tube->Ref);
- }
- }
- Unlock(t->Lock);
- if (tube != NULL)
- {
- TubeFlushEx(tube, true);
- SleepThread(100);
- TubeDisconnect(tube);
- ReleaseTube(tube);
- }
- TubeDisconnect(t->HaltTube2);
- TubeDisconnect(t->HaltTube3);
- Set(t->HaltEvent);
- WaitThread(t->Thread, INFINITE);
- ReleaseThread(t->Thread);
- DeleteLock(t->Lock);
- DeleteLock(t->CancelLock);
- ReleaseEvent(t->HaltEvent);
- ReleaseTube(t->HaltTube2);
- ReleaseTube(t->HaltTube3);
- NnClearQueue(t);
- ReleaseQueue(t->RecvQueue);
- ReleaseQueue(t->SendQueue);
- ReleaseCancel(t->Cancel);
- // Release the NAT table
- for (i = 0;i < LIST_NUM(t->NatTableForSend->AllList);i++)
- {
- NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForSend->AllList, i);
- Free(e);
- }
- ReleaseHashList(t->NatTableForSend);
- ReleaseHashList(t->NatTableForRecv);
- NnFreeIpCombineList(t);
- Free(t);
- }
- // Take the log of Virtual Host
- void VLog(VH *v, char *str)
- {
- // Not take!!
- return;
- }
- // Disconnect the NAT entry immediately
- void DisconnectNatEntryNow(VH *v, NAT_ENTRY *e)
- {
- // Validate arguments
- if (v == NULL || e == NULL)
- {
- return;
- }
- if (e->DisconnectNow == false)
- {
- e->DisconnectNow = true;
- SetSockEvent(v->SockEvent);
- }
- }
- // Get the NAT entry with specified source IP address and the oldest last communication time
- NAT_ENTRY *GetOldestNatEntryOfIp(VH *v, UINT ip, UINT protocol)
- {
- UINT i;
- NAT_ENTRY *oldest = NULL;
- UINT64 oldest_tick = 0xFFFFFFFFFFFFFFFFULL;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- for (i = 0;i < LIST_NUM(v->NatTable);i++)
- {
- NAT_ENTRY *e = LIST_DATA(v->NatTable, i);
- if (e->DisconnectNow == false)
- {
- if (e->SrcIp == ip)
- {
- if (e->Protocol == protocol)
- {
- if (protocol != NAT_TCP || e->TcpStatus != NAT_TCP_CONNECTING)
- {
- if (e->LastCommTime <= oldest_tick)
- {
- oldest_tick = e->LastCommTime;
- oldest = e;
- }
- }
- }
- }
- }
- }
- return oldest;
- }
- // Get the number of current NAT entries per IP address
- UINT GetNumNatEntriesPerIp(VH *v, UINT ip, UINT protocol, bool tcp_syn_sent)
- {
- UINT ret = 0;
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return 0;
- }
- for (i = 0;i < LIST_NUM(v->NatTable);i++)
- {
- NAT_ENTRY *e = LIST_DATA(v->NatTable, i);
- if (e->DisconnectNow == false)
- {
- if (e->SrcIp == ip)
- {
- if (e->Protocol == protocol)
- {
- bool ok = false;
- if (protocol == NAT_TCP)
- {
- if (tcp_syn_sent)
- {
- if (e->TcpStatus == NAT_TCP_CONNECTING)
- {
- ok = true;
- }
- }
- else
- {
- if (e->TcpStatus != NAT_TCP_CONNECTING)
- {
- ok = true;
- }
- }
- }
- else
- {
- ok = true;
- }
- if (ok)
- {
- ret++;
- }
- }
- }
- }
- }
- return ret;
- }
- // Check whether the NAT is available
- bool CanCreateNewNatEntry(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return false;
- }
- if (v->UseNat == false)
- {
- // NAT stopped
- return false;
- }
- if (NnIsActive(v) && v->NativeNat != NULL && v->NativeNat->NatTableForRecv != NULL)
- {
- if (v->NativeNat->NatTableForRecv->AllList->num_item > NAT_MAX_SESSIONS_KERNEL)
- {
- // Number of sessions exceeded (kernel mode)
- return false;
- }
- }
- else
- {
- if (v->NatTable->num_item > NAT_MAX_SESSIONS)
- {
- // Number of sessions exceeded (user mode)
- return false;
- }
- }
- return true;
- }
- // Set a pointer to the Virtual HUB options
- void NatSetHubOption(VH *v, HUB_OPTION *o)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- v->HubOption = o;
- }
- // Get a pointer to the Virtual HUB options
- HUB_OPTION *NatGetHubOption(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- return v->HubOption;
- }
- // The main function of NAT processing thread
- void NatThreadMain(VH *v)
- {
- bool halt_flag;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- v->TmpBuf = Malloc(NAT_TMPBUF_SIZE);
- while (true)
- {
- // Wait until the next event is set
- WaitSockEvent(v->SockEvent, SELECT_TIME);
- halt_flag = false;
- LockVirtual(v);
- {
- // Process on all NAT sessions
- UINT i, num;
- v->Now = Tick64();
- v->NatDoCancelFlag = false;
- LIST_ELEMENT_DELETED:
- num = LIST_NUM(v->NatTable);
- for (i = 0;i < num;i++)
- {
- NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
- switch (n->Protocol)
- {
- case NAT_TCP: // TCP
- if (NatTransactTcp(v, n) == false)
- {
- goto LIST_ELEMENT_DELETED;
- }
- break;
- case NAT_UDP: // UDP
- if (NatTransactUdp(v, n) == false)
- {
- goto LIST_ELEMENT_DELETED;
- }
- break;
- case NAT_ICMP: // ICMP
- if (NatTransactIcmp(v, n) == false)
- {
- goto LIST_ELEMENT_DELETED;
- }
- break;
- case NAT_DNS: // DNS
- if (NatTransactDns(v, n) == false)
- {
- goto LIST_ELEMENT_DELETED;
- }
- break;
- }
- }
- if (v->NatDoCancelFlag)
- {
- // Hit the cancel of the parent thread
- Cancel(v->Cancel);
- }
- // Halting flag check
- if (v->HaltNat)
- {
- halt_flag = true;
- }
- }
- UnlockVirtual(v);
- if (halt_flag)
- {
- // Terminate the thread by disconnecting all entries forcibly
- LockVirtual(v);
- {
- UINT num = LIST_NUM(v->NatTable);
- NAT_ENTRY **nn = ToArray(v->NatTable);
- UINT i;
- for (i = 0;i < num;i++)
- {
- NAT_ENTRY *n = nn[i];
- n->DisconnectNow = true;
- switch (n->Protocol)
- {
- case NAT_TCP: // TCP
- NatTransactTcp(v, n);
- break;
- case NAT_UDP: // UDP
- NatTransactUdp(v, n);
- break;
- case NAT_ICMP: // ICMP
- NatTransactIcmp(v, n);
- break;
- case NAT_DNS: // DNS
- NatTransactDns(v, n);
- break;
- }
- }
- Free(nn);
- }
- UnlockVirtual(v);
- break;
- }
- }
- Free(v->TmpBuf);
- }
- // DNS: Thread to get the IP address
- void NatGetIPThread(THREAD *t, void *param)
- {
- NAT_DNS_QUERY *q;
- // Validate arguments
- if (t == NULL || param == NULL)
- {
- return;
- }
- q = (NAT_DNS_QUERY *)param;
- AddWaitThread(t);
- q->Ok = GetIP(&q->Ip, q->Hostname);
- DelWaitThread(t);
- if (Release(q->ref) == 0)
- {
- Free(q);
- }
- }
- // DNS: Get an IP address from host name
- bool NatGetIP(IP *ip, char *hostname)
- {
- TOKEN_LIST *t;
- bool ret = false;
- // Validate arguments
- if (ip == NULL || hostname == NULL)
- {
- return false;
- }
- t = ParseToken(hostname, ".");
- if (t == NULL)
- {
- return false;
- }
- if (t->NumTokens == 0)
- {
- FreeToken(t);
- return false;
- }
- if (t->NumTokens == 1)
- {
- ret = GetIP(ip, hostname);
- }
- else
- {
- char *hostname2 = t->Token[0];
- NAT_DNS_QUERY *q1, *q2;
- THREAD *t1, *t2;
- q1 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
- q2 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
- q1->ref = NewRef();
- q2->ref = NewRef();
- AddRef(q1->ref);
- AddRef(q2->ref);
- StrCpy(q1->Hostname, sizeof(q1->Hostname), hostname);
- StrCpy(q2->Hostname, sizeof(q2->Hostname), hostname2);
- t1 = NewThread(NatGetIPThread, q1);
- t2 = NewThread(NatGetIPThread, q2);
- WaitThread(t1, NAT_DNS_QUERY_TIMEOUT);
- if (q1->Ok)
- {
- ret = true;
- Copy(ip, &q1->Ip, sizeof(IP));
- }
- else
- {
- WaitThread(t2, NAT_DNS_QUERY_TIMEOUT);
- if (q1->Ok)
- {
- ret = true;
- Copy(ip, &q1->Ip, sizeof(IP));
- }
- else if (q2->Ok)
- {
- ret = true;
- Copy(ip, &q2->Ip, sizeof(IP));
- }
- }
- ReleaseThread(t1);
- ReleaseThread(t2);
- if (Release(q1->ref) == 0)
- {
- Free(q1);
- }
- if (Release(q2->ref) == 0)
- {
- Free(q2);
- }
- }
- FreeToken(t);
- return ret;
- }
- // DNS query function
- void NatDnsThread(THREAD *t, void *param)
- {
- NAT_ENTRY *n;
- IP ip;
- // Validate arguments
- if (t == NULL || param == NULL)
- {
- return;
- }
- n = (NAT_ENTRY *)param;
- // Notify the initialization completion
- NoticeThreadInit(t);
- // Run processing
- if (EndWith(n->DnsTargetHostName, ".in-addr.arpa") == false)
- {
- // Forward resolution
- if (NatGetIP(&ip, n->DnsTargetHostName))
- {
- // Forward resolution success
- Copy(&n->DnsResponseIp, &ip, sizeof(IP));
- n->DnsOk = true;
- }
- }
- else
- {
- // Reverse resolution
- IP ip;
- n->DnsGetIpFromHost = true; // Set the reverse resolution flag
- // Convert a *.in-addr.arpa string to an IP address
- if (ArpaToIP(&ip, n->DnsTargetHostName))
- {
- // Reverse resolution process
- char tmp[256];
- if (GetHostName(tmp, sizeof(tmp), &ip))
- {
- // Reverse resolution success
- n->DnsResponseHostName = CopyStr(tmp);
- n->DnsOk = true;
- }
- }
- }
- // Notify the results
- n->DnsFinished = true;
- SetSockEvent(n->v->SockEvent);
- }
- // Convert a reverse resolution address to an IP address
- bool ArpaToIP(IP *ip, char *str)
- {
- TOKEN_LIST *token;
- bool ret = false;
- // Validate arguments
- if (ip == NULL || str == NULL)
- {
- return false;
- }
- // Token conversion
- token = ParseToken(str, ".");
- if (token->NumTokens == 6)
- {
- // Convert the token [0, 1, 2, 3] to IP
- UINT i;
- Zero(ip, sizeof(IP));
- for (i = 0;i < 4;i++)
- {
- ip->addr[i] = (UCHAR)ToInt(token->Token[3 - i]);
- }
- ret = true;
- }
- FreeToken(token);
- if (IPToUINT(ip) == 0)
- {
- ret = false;
- }
- return ret;
- }
- // Handle a DNS entry
- bool NatTransactDns(VH *v, NAT_ENTRY *n)
- {
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return true;
- }
- if (n->DisconnectNow)
- {
- goto DISCONNECT;
- }
- if (n->DnsThread == NULL && n->DnsFinished == false)
- {
- // Create a thread
- THREAD *t = NewThread(NatDnsThread, (void *)n);
- WaitThreadInit(t);
- n->DnsThread = t;
- }
- else
- {
- // Wait for the result
- if (n->DnsFinished)
- {
- // Results have been received
- WaitThread(n->DnsThread, INFINITE);
- ReleaseThread(n->DnsThread);
- n->DnsThread = NULL;
- // Notify to the main thread
- v->NatDoCancelFlag = true;
- }
- }
- return true;
- DISCONNECT:
- // Releasing process
- if (n->DnsThread != NULL)
- {
- WaitThread(n->DnsThread, INFINITE);
- ReleaseThread(n->DnsThread);
- n->DnsThread = NULL;
- }
- if (n->DnsTargetHostName != NULL)
- {
- Free(n->DnsTargetHostName);
- n->DnsTargetHostName = NULL;
- }
- if (n->DnsResponseHostName != NULL)
- {
- Free(n->DnsResponseHostName);
- n->DnsResponseHostName = NULL;
- }
- DeleteLock(n->lock);
- Delete(v->NatTable, n);
- Free(n);
- return false;
- }
- // ICMP thread procedure
- void NatIcmpThreadProc(THREAD *thread, void *param)
- {
- NAT_ENTRY *n;
- ICMP_RESULT *ret = NULL;
- USHORT src_id = 0, src_seqno = 0;
- // Validate arguments
- if (thread == NULL || param == NULL)
- {
- return;
- }
- n = (NAT_ENTRY *)param;
- if (n->IcmpQueryBlock)
- {
- UCHAR *data = n->IcmpQueryBlock->Buf;
- UINT size = n->IcmpQueryBlock->Size;
- if (size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
- {
- ICMP_HEADER *icmp = (ICMP_HEADER *)data;
- ICMP_ECHO *echo = (ICMP_ECHO *)(data + sizeof(ICMP_HEADER));
- if (icmp->Type == ICMP_TYPE_ECHO_REQUEST && icmp->Code == 0)
- {
- UCHAR *icmp_payload = data + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
- UINT icmp_payload_size = size - sizeof(ICMP_HEADER) - sizeof(ICMP_ECHO);
- IP dest_ip;
- src_id = Endian16(echo->Identifier);
- src_seqno = Endian16(echo->SeqNo);
- UINTToIP(&dest_ip, n->DestIp);
- // Send a query by using the ICMP API
- ret = IcmpApiEchoSend(&dest_ip, n->IcmpQueryBlock->Ttl,
- icmp_payload, icmp_payload_size, NAT_ICMP_TIMEOUT_WITH_API);
- }
- }
- }
- if (ret != NULL && ret->Timeout == false)
- {
- // Convert to an IPv4 + ICMP packet since the result of ICMP API was obtained
- IPV4_HEADER ipv4;
- ICMP_HEADER icmp;
- ICMP_ECHO echo;
- BUF *buf = NewBuf();
- // IPv4 header
- Zero(&ipv4, sizeof(ipv4));
- IPV4_SET_VERSION(&ipv4, 4);
- IPV4_SET_HEADER_LEN(&ipv4, sizeof(IPV4_HEADER) / 4);
- ipv4.TimeToLive = ret->Ttl;
- ipv4.Protocol = IP_PROTO_ICMPV4;
- ipv4.SrcIP = IPToUINT(&ret->IpAddress);
- ipv4.DstIP = 0x01010101;
- // ICMP header
- Zero(&icmp, sizeof(icmp));
- Zero(&echo, sizeof(echo));
- if (ret->Ok)
- {
- // Normal response
- echo.Identifier = Endian16(src_id);
- echo.SeqNo = Endian16(src_seqno);
- ipv4.TotalLength = Endian16((USHORT)(sizeof(ipv4) + sizeof(icmp) + sizeof(echo) + ret->DataSize));
- WriteBuf(buf, &ipv4, sizeof(ipv4));
- WriteBuf(buf, &icmp, sizeof(icmp));
- WriteBuf(buf, &echo, sizeof(echo));
- WriteBuf(buf, ret->Data, ret->DataSize);
- }
- else
- {
- // Error reply
- icmp.Type = ret->Type;
- icmp.Code = ret->Code;
- echo.Identifier = Endian16(src_id);
- echo.SeqNo = Endian16(src_seqno);
- ipv4.TotalLength = Endian16((USHORT)(sizeof(ipv4) + sizeof(icmp) + sizeof(echo) + n->IcmpOriginalCopySize));
- WriteBuf(buf, &ipv4, sizeof(ipv4));
- WriteBuf(buf, &icmp, sizeof(icmp));
- WriteBuf(buf, &echo, sizeof(echo));
- // Copy of the original packet to be included in the response packet
- WriteBuf(buf, n->IcmpOriginalCopy, n->IcmpOriginalCopySize);
- }
- n->IcmpResponseBlock = NewBlock(Clone(buf->Buf, buf->Size), buf->Size, 0);
- n->IcmpResponseBlock->Ttl = ret->Ttl;
- FreeBuf(buf);
- }
- IcmpApiFreeResult(ret);
- // Inform the completion of the processing
- n->IcmpTaskFinished = true;
- SetSockEvent(n->v->SockEvent);
- }
- // Process ICMP entry
- bool NatTransactIcmp(VH *v, NAT_ENTRY *n)
- {
- void *buf;
- UINT recv_size;
- BLOCK *block;
- UINT dest_port = n->DestPort;
- IP dest_ip;
- UINT num_ignore_errors = 0;
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return true;
- }
- if (n->DisconnectNow)
- {
- goto DISCONNECT;
- }
- if (v->IcmpRawSocketOk)
- {
- // Environment that the Raw sockets are available
- if (n->UdpSocketCreated == false)
- {
- // Create a UDP socket
- n->Sock = NewUDP(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4));
- if (n->Sock == NULL)
- {
- // Socket creation failure
- goto DISCONNECT;
- }
- else
- {
- n->PublicIp = IPToUINT(&n->Sock->LocalIP);
- n->PublicPort = n->Sock->LocalPort;
- JoinSockToSockEvent(n->Sock, v->SockEvent);
- n->UdpSocketCreated = true;
- }
- }
- }
- else
- {
- // Create a thread for using ICMP API if Raw sockets are not available
- if (n->IcmpThread == NULL)
- {
- if (n->UdpSendQueue->num_item >= 1)
- {
- // Since UdpSendQueue contains only 1 query, get a first query
- // and create a thread and pass the query to the thread
- BLOCK *block = GetNext(n->UdpSendQueue);
- n->IcmpQueryBlock = block;
- n->IcmpThread = NewThread(NatIcmpThreadProc, n);
- }
- }
- if (n->IcmpTaskFinished)
- {
- if (n->IcmpResponseBlock != NULL)
- {
- // Because there was a response from the thread that calls ICMP API, pass this result to the stack
- block = n->IcmpResponseBlock;
- n->IcmpResponseBlock = NULL;
- InsertQueue(n->UdpRecvQueue, block);
- v->NatDoCancelFlag = true;
- n->LastCommTime = v->Now;
- }
- else
- {
- // Disconnect immediately when it fails
- goto DISCONNECT;
- }
- }
- // Examine whether this session timed-out
- if ((n->LastCommTime + (UINT64)NAT_ICMP_TIMEOUT_WITH_API) < v->Now || n->LastCommTime > v->Now)
- {
- // Time-out
- goto DISCONNECT;
- }
- return true;
- }
- // Following are processed only for if the raw sockets are available
- buf = v->TmpBuf;
- UINTToIP(&dest_ip, n->DestIp);
- // Try to receive data from the UDP socket
- while (true)
- {
- IP src_ip;
- UINT src_port;
- recv_size = RecvFrom(n->Sock, &src_ip, &src_port, buf, 65536);
- if (recv_size == SOCK_LATER)
- {
- // Packet has not arrived
- break;
- }
- else if (recv_size == 0)
- {
- Debug("ICMP ERROR\n");
- // Error?
- if (n->Sock->IgnoreRecvErr == false)
- {
- // A fatal error occurred
- goto DISCONNECT;
- }
- else
- {
- if ((num_ignore_errors++) >= MAX_NUM_IGNORE_ERRORS)
- {
- goto DISCONNECT;
- }
- }
- }
- else
- {
- // Analyze the arriving packet
- ICMP_RESULT *ret = IcmpParseResult(&dest_ip, n->SrcPort, 0, buf, recv_size);
- if (ret != NULL)
- {
- if ((ret->Ok && CmpIpAddr(&ret->IpAddress, &dest_ip) == 0) ||
- (ret->DataSize >= sizeof(IPV4_HEADER) && ((IPV4_HEADER *)ret->Data)->DstIP == n->DestIp))
- {
- // Insert to the queue
- void *data = Malloc(recv_size);
- Copy(data, buf, recv_size);
- block = NewBlock(data, recv_size, 0);
- InsertQueue(n->UdpRecvQueue, block);
- v->NatDoCancelFlag = true;
- n->LastCommTime = v->Now;
- }
- IcmpFreeResult(ret);
- }
- }
- }
- // Try to send data to the UDP socket
- while (block = GetNext(n->UdpSendQueue))
- {
- // Assemble the Echo header and ICMP header
- UINT send_size;
- SetTtl(n->Sock, block->Ttl);
- send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
- FreeBlock(block);
- if (send_size == 0)
- {
- Debug("ICMP ERROR\n");
- // Determine whether a fatal error
- if (n->Sock->IgnoreSendErr == false)
- {
- // A fatal error occurred
- goto DISCONNECT;
- }
- }
- else
- {
- n->LastCommTime = v->Now;
- }
- }
- // Examine whether this session timed-out
- if ((n->LastCommTime + (UINT64)NAT_ICMP_TIMEOUT) < v->Now || n->LastCommTime > v->Now)
- {
- // Time-out
- goto DISCONNECT;
- }
- return true;
- DISCONNECT:
- // Disconnect this session
- if (n->UdpSocketCreated)
- {
- // Close the socket
- Disconnect(n->Sock);
- ReleaseSock(n->Sock);
- n->Sock = NULL;
- }
- // Terminate if the thread has been created
- if (n->IcmpThread != NULL)
- {
- WaitThread(n->IcmpThread, INFINITE);
- ReleaseThread(n->IcmpThread);
- n->IcmpThread = NULL;
- }
- // Delete the entry
- DeleteNatIcmp(v, n);
- return false;
- }
- // Process the UDP entry
- bool NatTransactUdp(VH *v, NAT_ENTRY *n)
- {
- void *buf;
- UINT recv_size;
- BLOCK *block;
- UINT dest_port = n->DestPort;
- IP dest_ip;
- UINT num_ignore_errors;
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return true;
- }
- if (n->DisconnectNow)
- {
- goto DISCONNECT;
- }
- if (n->UdpSocketCreated == false)
- {
- // Create a UDP socket
- n->Sock = NewUDP(0);
- if (n->Sock == NULL)
- {
- // Socket creation failure
- goto DISCONNECT;
- }
- else
- {
- n->PublicIp = IPToUINT(&n->Sock->LocalIP);
- n->PublicPort = n->Sock->LocalPort;
- JoinSockToSockEvent(n->Sock, v->SockEvent);
- n->UdpSocketCreated = true;
- }
- }
- buf = v->TmpBuf;
- if (n->ProxyDns == false)
- {
- UINTToIP(&dest_ip, n->DestIp);
- }
- else
- {
- UINTToIP(&dest_ip, n->DestIpProxy);
- }
- num_ignore_errors = 0;
- // Try to receive data from the UDP socket
- while (true)
- {
- IP src_ip;
- UINT src_port;
- recv_size = RecvFrom(n->Sock, &src_ip, &src_port, buf, 65536);
- if (recv_size == SOCK_LATER)
- {
- // Packet has not arrived
- break;
- }
- else if (recv_size == 0)
- {
- // Error?
- if (n->Sock->IgnoreRecvErr == false)
- {
- // A fatal error occurred
- goto DISCONNECT;
- }
- else
- {
- if ((num_ignore_errors++) > MAX_NUM_IGNORE_ERRORS)
- {
- goto DISCONNECT;
- }
- }
- }
- else
- {
- // Packet arrives. Check the source IP
- if (IPToUINT(&src_ip) == n->DestIp || n->DestIp == 0xFFFFFFFF || (IPToUINT(&src_ip) == n->DestIpProxy && n->ProxyDns) && src_port == n->DestPort)
- {
- // Insert to the queue
- void *data = Malloc(recv_size);
- Copy(data, buf, recv_size);
- block = NewBlock(data, recv_size, 0);
- if (block != NULL)
- {
- if (src_port == SPECIAL_UDP_PORT_WSD || src_port == SPECIAL_UDP_PORT_SSDP)
- {
- // Make believe there is a response from the host really in the case of WSD packet
- block->Param1 = IPToUINT(&src_ip);
- }
- }
- InsertQueue(n->UdpRecvQueue, block);
- v->NatDoCancelFlag = true;
- n->LastCommTime = v->Now;
- }
- }
- }
- // Try to send data to the UDP socket
- while (block = GetNext(n->UdpSendQueue))
- {
- UINT send_size;
- bool is_nbtdgm = false;
- LIST *local_ip_list = NULL;
-
- if (dest_port == SPECIAL_UDP_PORT_NBTDGM)
- {
- // Determine whether NetBIOS Datagram packet
- NBTDG_HEADER *nh = (NBTDG_HEADER *)block->Buf;
- if (nh != NULL && block->Size >= sizeof(NBTDG_HEADER))
- {
- if (nh->SrcIP == n->SrcIp && Endian16(nh->SrcPort) == n->SrcPort)
- {
- local_ip_list = GetHostIPAddressList();
- if (local_ip_list != NULL)
- {
- is_nbtdgm = true;
- }
- }
- }
- }
- if (is_nbtdgm == false)
- {
- // Normal UDP packet
- send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
- }
- else
- {
- // IP address and port number is embedded in the NetBIOS Datagram Packet.
- // Transfer by rewriting it properly
- UINT i;
- for (i = 0;i < LIST_NUM(local_ip_list);i++)
- {
- IP *my_ip = LIST_DATA(local_ip_list, i);
- if (IsIP4(my_ip) && IsZeroIp(my_ip) == false && IsLocalHostIP(my_ip) == false)
- {
- NBTDG_HEADER *nh = (NBTDG_HEADER *)block->Buf;
- nh->SrcIP = IPToUINT(my_ip);
- nh->SrcPort = Endian16(n->PublicPort);
- send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
- }
- }
- }
- if (local_ip_list != NULL)
- {
- FreeHostIPAddressList(local_ip_list);
- }
- FreeBlock(block);
- if (send_size == 0)
- {
- // Determining whether a fatal error
- if (n->Sock->IgnoreSendErr == false)
- {
- // A fatal error occurred
- goto DISCONNECT;
- }
- }
- else
- {
- n->LastCommTime = v->Now;
- }
- }
- // Examine whether this session timed-out
- if ((n->LastCommTime + (UINT64)v->NatUdpTimeout) < v->Now || n->LastCommTime > v->Now)
- {
- // Time-out
- goto DISCONNECT;
- }
- return true;
- DISCONNECT:
- // Disconnect this session
- if (n->UdpSocketCreated)
- {
- // Close the socket
- Disconnect(n->Sock);
- ReleaseSock(n->Sock);
- n->Sock = NULL;
- }
- // Delete the entry
- DeleteNatUdp(v, n);
- return false;
- }
- // Thread to make a connection to the TCP host
- void NatTcpConnectThread(THREAD *t, void *p)
- {
- NAT_ENTRY *n = (NAT_ENTRY *)p;
- IP ip;
- char hostname[MAX_SIZE];
- UINT port_number;
- SOCK *sock;
- SOCK_EVENT *e;
- // Validate arguments
- if (n == NULL || t == NULL)
- {
- return;
- }
- UINTToIP(&ip, n->DestIp);
- IPToStr(hostname, sizeof(hostname), &ip);
- port_number = n->DestPort;
- e = n->v->SockEvent;
- AddRef(e->ref);
- // Notify the initialization completion
- NoticeThreadInit(t);
- // Attempt to connect to the TCP host
- Debug("NatTcpConnect Connecting to %s:%u\n", hostname, port_number);
- sock = ConnectEx3(hostname, port_number, 0, &n->NatTcpCancelFlag, NULL, NULL, false, false, true);
- if (sock == NULL)
- {
- // Connection failure
- n->TcpMakeConnectionFailed = true;
- }
- else
- {
- // Successful connection
- n->TcpMakeConnectionSucceed = true;
- }
- n->Sock = sock;
- JoinSockToSockEvent(sock, e);
- SetSockEvent(e);
- ReleaseSockEvent(e);
- }
- // Create a thread for trying to connect to the TCP host
- void CreateNatTcpConnectThread(VH *v, NAT_ENTRY *n)
- {
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- // Create a thread
- n->NatTcpConnectThread = NewThread(NatTcpConnectThread, (void *)n);
- // Wait for a thread initialization completion
- WaitThreadInit(n->NatTcpConnectThread);
- }
- // Handle the TCP entry
- bool NatTransactTcp(VH *v, NAT_ENTRY *n)
- {
- char str[MAX_SIZE];
- bool timeouted = false;
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return false;
- }
- if (n->DisconnectNow)
- {
- goto DISCONNECT;
- }
- // Process by state of the TCP
- switch (n->TcpStatus)
- {
- case NAT_TCP_CONNECTING: // Waiting for connection
- if (n->NatTcpConnectThread == NULL)
- {
- // Start a connection by creating a connection thread
- CreateNatTcpConnectThread(v, n);
- }
- else
- {
- // Wait for the result of the connection thread that has already started
- if (n->TcpMakeConnectionFailed || n->TcpMakeConnectionSucceed)
- {
- // Use the results because operation thread has already finished
- WaitThread(n->NatTcpConnectThread, INFINITE);
- ReleaseThread(n->NatTcpConnectThread);
- n->NatTcpConnectThread = NULL;
- if (n->TcpMakeConnectionSucceed)
- {
- // Connection is successful, and a Sock was created
- n->TcpStatus = NAT_TCP_CONNECTED;
- IPToStr32(str, sizeof(str), n->DestIp);
- NLog(v, "LH_NAT_TCP_SUCCEED", n->Id, n->Sock->RemoteHostname, str, n->DestPort);
- }
- else
- {
- // Failed to connect
- n->TcpStatus = NAT_TCP_SEND_RESET;
- IPToStr32(str, sizeof(str), n->DestIp);
- NLog(v, "LH_NAT_TCP_FAILED", n->Id, str, n->DestPort);
- }
- v->NatDoCancelFlag = true;
- }
- }
- break;
- case NAT_TCP_CONNECTED: // TCP socket connection completed. Negotiating with the client host
- break;
- case NAT_TCP_SEND_RESET: // TCP communication disconnection: Send a RST to the client host
- break;
- case NAT_TCP_ESTABLISHED: // TCP connection established
- {
- UINT old_send_fifo_size = 0;
- // Transmit to the socket if there is data in the receive buffer
- while (n->RecvFifo->size > 0)
- {
- UINT sent_size = Send(n->Sock, ((UCHAR *)n->RecvFifo->p) + n->RecvFifo->pos,
- n->RecvFifo->size, false);
- if (sent_size == 0)
- {
- // Communication has been disconnected
- n->TcpFinished = true;
- v->NatDoCancelFlag = true;
- break;
- }
- else if (sent_size == SOCK_LATER)
- {
- // Blocking
- break;
- }
- else
- {
- // Successful transmission
- ReadFifo(n->RecvFifo, NULL, sent_size);
- n->SendAckNext = true;
- if (false)
- {
- IP ip;
- n->test_TotalSent += sent_size;
- UINTToIP(&ip, n->DestIp);
- Debug("TCP %u: %r:%u %u\n", n->Id, &ip, n->DestPort, (UINT)n->test_TotalSent);
- }
- }
- }
- old_send_fifo_size = FifoSize(n->SendFifo);
- // Write to the transmission buffer by obtaining data from the socket
- while (true)
- {
- void *buf = (void *)v->TmpBuf;
- UINT want_to_recv_size = 0;
- UINT recv_size;
- // Calculate the size of wanting to receive
- if (n->SendFifo->size < NAT_SEND_BUF_SIZE)
- {
- // Still can receive
- want_to_recv_size = MIN(NAT_SEND_BUF_SIZE - n->SendFifo->size, NAT_TMPBUF_SIZE);
- }
- if (want_to_recv_size == 0)
- {
- SetNoNeedToRead(n->Sock);
- break;
- }
- recv_size = Recv(n->Sock, buf, want_to_recv_size, false);
- if (recv_size == 0)
- {
- // Communication has been disconnected
- n->TcpFinished = true;
- v->NatDoCancelFlag = true;
- if (n->TcpDisconnected == false)
- {
- Disconnect(n->Sock);
- n->TcpDisconnected = true;
- }
- break;
- }
- else if (recv_size == SOCK_LATER)
- {
- // Blocking
- break;
- }
- else
- {
- // Successful reception
- WriteFifo(n->SendFifo, buf, recv_size);
- v->NatDoCancelFlag = true;
- }
- }
- if (old_send_fifo_size == 0 && FifoSize(n->SendFifo) != 0)
- {
- // Reset the time data for timeout when the data is newly queued
- // in the empty transmission buffer in the transmission process
- n->TcpLastRecvAckTime = v->Now;
- }
- // Raise a transmission time-out if a certain period of time elapsed
- // after receiving the last ACK, and the transmission buffer is not
- // empty, and the reception window size of other party is not 0
- if ((n->TcpLastRecvAckTime + (UINT64)VIRTUAL_TCP_SEND_TIMEOUT) < v->Now)
- {
- if (FifoSize(n->SendFifo) != 0 && n->TcpSendWindowSize != 0)
- {
- timeouted = true;
- }
- }
- }
- break;
- }
- // Timeout Detection
- if ((n->LastCommTime + (UINT64)v->NatTcpTimeout) < v->Now || n->LastCommTime > v->Now)
- {
- timeouted = true;
- }
- if (timeouted)
- {
- // Time-out occurs, the session close
- n->TcpStatus = NAT_TCP_SEND_RESET;
- v->NatDoCancelFlag = true;
- }
- return true;
- DISCONNECT: // Disconnect and session disposal
- DeleteNatTcp(v, n);
- return false;
- }
- // Delete the entry of TCP NAT
- void DeleteNatTcp(VH *v, NAT_ENTRY *n)
- {
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- NLog(v, "LH_NAT_TCP_DELETED", n->Id);
- // Shutdown of connection thread
- if (n->NatTcpConnectThread != NULL)
- {
- n->NatTcpCancelFlag = true;
- WaitThread(n->NatTcpConnectThread, INFINITE);
- ReleaseThread(n->NatTcpConnectThread);
- n->NatTcpConnectThread = NULL;
- }
- if (n->Sock != NULL)
- {
- // Disconnect the socket
- Disconnect(n->Sock);
- ReleaseSock(n->Sock);
- n->Sock = NULL;
- }
- // Release the window memory
- if (n->TcpRecvWindow != NULL)
- {
- ReleaseFifo(n->TcpRecvWindow);
- n->TcpRecvWindow = NULL;
- }
- // Release the window reception list
- if (n->TcpRecvList != NULL)
- {
- UINT i;
- for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
- {
- IP_PART *p = LIST_DATA(n->TcpRecvList, i);
- Free(p);
- }
- ReleaseList(n->TcpRecvList);
- n->TcpRecvList = NULL;
- }
- // FIFO release
- ReleaseFifo(n->SendFifo);
- ReleaseFifo(n->RecvFifo);
- // Delete from the NAT entry
- Delete(v->NatTable, n);
- DeleteLock(n->lock);
- // Release the memory
- Free(n);
- Debug("NAT_ENTRY: DeleteNatTcp\n");
- }
- // NAT processing thread
- void NatThread(THREAD *t, void *param)
- {
- // Validate arguments
- if (t == NULL || param == NULL)
- {
- return;
- }
- // Notify the initialization completion
- NoticeThreadInit(t);
- NatThreadMain((VH *)param);
- }
- // Send a beacon packet
- void SendBeacon(VH *v)
- {
- UINT dest_ip;
- ARPV4_HEADER arp;
- static char beacon_str[] =
- "SecureNAT Virtual TCP/IP Stack Beacon";
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Send an UDP
- dest_ip = (v->HostIP & v->HostMask) | (~v->HostMask);
- SendUdp(v, dest_ip, 7, v->HostIP, 7, beacon_str, sizeof(beacon_str));
- // Build the ARP header
- arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
- arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
- arp.HardwareSize = 6;
- arp.ProtocolSize = 4;
- arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
- Copy(arp.SrcAddress, v->MacAddress, 6);
- arp.SrcIP = v->HostIP;
- arp.TargetAddress[0] =
- arp.TargetAddress[1] =
- arp.TargetAddress[2] =
- arp.TargetAddress[3] =
- arp.TargetAddress[4] =
- arp.TargetAddress[5] = 0xff;
- arp.TargetIP = dest_ip;
- // Transmission
- VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
- }
- // Send a TCP packet
- void SendTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss, void *data, UINT size)
- {
- static UCHAR tcp_mss_option[] = {0x02, 0x04, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00};
- IPV4_PSEUDO_HEADER *vh;
- TCP_HEADER *tcp;
- UINT header_size = TCP_HEADER_SIZE;
- UINT total_size;
- // Validate arguments
- if (v == NULL || (size != 0 && data == NULL))
- {
- return;
- }
- // Memory allocation
- vh = Malloc(sizeof(IPV4_PSEUDO_HEADER) + TCP_HEADER_SIZE + size + 32);
- tcp = (TCP_HEADER *)(((UCHAR *)vh) + sizeof(IPV4_PSEUDO_HEADER));
- if (mss != 0)
- {
- USHORT *mss_size;
- mss_size = (USHORT *)(&tcp_mss_option[2]);
- *mss_size = Endian16((USHORT)mss);
- header_size += sizeof(tcp_mss_option);
- }
- total_size = header_size + size;
- if (total_size > 65536)
- {
- // Packet is too long
- Free(vh);
- return;
- }
- // Pseudo header generation
- vh->SrcIP = src_ip;
- vh->DstIP = dest_ip;
- vh->Reserved = 0;
- vh->Protocol = IP_PROTO_TCP;
- vh->PacketLength = Endian16((USHORT)total_size);
- // TCP header generation
- tcp->SrcPort = Endian16((USHORT)src_port);
- tcp->DstPort = Endian16((USHORT)dest_port);
- tcp->SeqNumber = Endian32(seq);
- tcp->AckNumber = Endian32(ack);
- tcp->HeaderSizeAndReserved = 0;
- TCP_SET_HEADER_SIZE(tcp, (UCHAR)(header_size / 4));
- tcp->Flag = (UCHAR)flag;
- tcp->WindowSize = Endian16((USHORT)window_size);
- tcp->Checksum = 0;
- tcp->UrgentPointer = 0;
- // Copy the option values
- if (mss != 0)
- {
- Copy(((UCHAR *)tcp) + TCP_HEADER_SIZE, tcp_mss_option, sizeof(tcp_mss_option));
- }
- // Data copy
- Copy(((UCHAR *)tcp) + header_size, data, size);
- // Checksum calculation
- tcp->Checksum = IpChecksum(vh, total_size + 12);
- // Submit as an IP packet
- SendIp(v, dest_ip, src_ip, IP_PROTO_TCP, tcp, total_size);
- // Release the memory
- Free(vh);
- }
- // Polling process of TCP
- void PollingNatTcp(VH *v, NAT_ENTRY *n)
- {
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- switch (n->TcpStatus)
- {
- case NAT_TCP_CONNECTING: // Socket connecting: nothing to do
- break;
- case NAT_TCP_CONNECTED: // The socket connected: process SYN + ACK, ACK
- if ((n->LastSynAckSentTime > v->Now) || n->LastSynAckSentTime == 0 || ((n->LastSynAckSentTime + (UINT64)(NAT_TCP_SYNACK_SEND_TIMEOUT * (UINT64)(n->SynAckSentCount + 1)) <= v->Now)))
- {
- n->LastSynAckSentTime = v->Now;
- // Send a SYN + ACK
- SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
- (UINT)(n->SendSeqInit + n->SendSeq),
- (UINT)(n->RecvSeqInit + n->RecvSeq),
- TCP_SYN | TCP_ACK, n->TcpRecvWindowSize,
- v->TcpMss, NULL, 0);
- n->SynAckSentCount++;
- }
- break;
- case NAT_TCP_SEND_RESET: // Reset the connection
- // Send a RST
- if (n->TcpFinished == false || n->TcpForceReset)
- {
- SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
- (UINT)(n->SendSeq + n->SendSeqInit),
- (UINT)(n->SendSeq + n->SendSeqInit),
- TCP_RST, 0,
- 0, NULL, 0);
- // Disconnect
- n->TcpStatus = NAT_TCP_WAIT_DISCONNECT;
- n->DisconnectNow = true;
- }
- else
- {
- // Send FINs for NAT_FIN_SEND_MAX_COUNT times
- if (n->FinSentTime == 0 || (n->FinSentTime > v->Now) || (n->FinSentTime + NAT_FIN_SEND_INTERVAL * (n->FinSentCount + 1)) < v->Now)
- {
- SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
- (UINT)(n->SendSeq + n->SendSeqInit),
- (UINT)(n->RecvSeq + n->RecvSeqInit),
- TCP_ACK | TCP_FIN, 0,
- 0, NULL, 0);
- n->FinSentTime = v->Now;
- n->FinSentSeq = (UINT)(n->SendSeq + n->SendSeqInit);
- n->FinSentCount++;
- if (n->FinSentCount >= NAT_FIN_SEND_MAX_COUNT)
- {
- n->TcpFinished = false;
- }
- }
- }
- break;
- case NAT_TCP_ESTABLISHED: // Connection established
- {
- UINT send_data_size;
- UINT current_pointer;
- UINT notice_window_size_value = 0;
- UINT buf_free_bytes = 0;
- // Determine the value of the window size to be notified
- if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
- {
- buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
- }
- notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
- if (n->LastSentKeepAliveTime == 0 ||
- (n->LastSentKeepAliveTime + (UINT64)NAT_ACK_KEEPALIVE_SPAN) < v->Now ||
- (n->LastSentKeepAliveTime > v->Now))
- {
- if (n->LastSentKeepAliveTime != 0)
- {
- // Send an ACK packet for Keep-Alive
- SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
- (UINT)(n->SendSeqInit + n->SendSeq),
- (UINT)(n->RecvSeqInit + n->RecvSeq) - 1,
- TCP_ACK,
- notice_window_size_value,
- 0,
- NULL,
- 0);
- }
- n->LastSentKeepAliveTime = v->Now;
- }
- if (n->TcpLastSentTime == 0 ||
- (n->TcpLastSentTime > v->Now) ||
- ((n->TcpLastSentTime + (UINT64)n->TcpSendTimeoutSpan) < v->Now) ||
- n->SendAckNext)
- {
- // If there is data to send, send the data
- // Calculate the segment size to be transmitted
- send_data_size = n->TcpSendWindowSize;
- if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
- {
- // Apply the cwnd value
- send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
- }
- if (send_data_size > n->SendFifo->size)
- {
- // Can not be sent over the data that is currently held
- send_data_size = n->SendFifo->size;
- }
- if (send_data_size >= 1)
- {
- // Transmit the fragmented segments
- current_pointer = 0;
- while (send_data_size > 0)
- {
- UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
- void *send_segment = (void *)(((UCHAR *)n->SendFifo->p) + n->SendFifo->pos + current_pointer);
- SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
- (UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer),
- (UINT)(n->RecvSeqInit + n->RecvSeq),
- TCP_ACK | TCP_PSH,
- notice_window_size_value,
- 0,
- send_segment,
- send_segment_size);
- current_pointer += send_segment_size;
- send_data_size -= send_segment_size;
- }
- // Record the transmission time
- n->TcpLastSentTime = v->Now;
- // Record the stream size to be transmitted this time
- n->SendMissionSize = current_pointer;
- n->CurrentSendingMission = true;
- // RTT measurement
- if (n->CalcRTTStartTime == 0)
- {
- n->CalcRTTStartTime = v->Now;
- n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
- }
- if (n->RetransmissionUsedFlag == false)
- {
- n->RetransmissionUsedFlag = true;
- }
- else
- {
- // Congestion is detected
- if (n->TcpSendCWnd > 2)
- {
- n->TcpSendCWnd--;
- }
- }
- }
- else if (n->SendAckNext)
- {
- // Send only an ACK
- SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
- (UINT)(n->SendSeqInit + n->SendSeq),
- (UINT)(n->RecvSeqInit + n->RecvSeq),
- TCP_ACK,
- notice_window_size_value,
- 0,
- NULL,
- 0);
- }
- n->SendAckNext = false;
- }
- if (n->TcpFinished)
- {
- // Disconnect if all data transmission has completed
- if (n->SendFifo->size == 0)
- {
- n->TcpStatus = NAT_TCP_SEND_RESET;
- }
- }
- }
- break;
- }
- }
- // Reception of TCP packets addressed to the Internet
- void TcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *tcp, void *data, UINT size, UINT max_l3_size)
- {
- NAT_ENTRY *n, t;
- UINT seq, ack;
- UINT64 seq64 = 0, ack64 = 0;
- // Validate arguments
- if (v == NULL || tcp == NULL || data == NULL)
- {
- return;
- }
- if (NnIsActive(v))
- {
- NnTcpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, tcp, data, size, max_l3_size);
- return;
- }
- seq = Endian32(tcp->SeqNumber);
- ack = Endian32(tcp->AckNumber);
- if (v->HubOption != NULL && v->HubOption->DisableUserModeSecureNAT)
- {
- // Disable User-mode NAT
- SendTcp(v, dest_ip, dest_port, src_ip, src_port,
- 0, seq + 1, TCP_RST | TCP_ACK, 0, 0, NULL, 0);
- return;
- }
- // Search for a session for this packet from the NAT table
- SetNat(&t, NAT_TCP, src_ip, src_port, dest_ip, dest_port, 0, 0);
- n = SearchNat(v, &t);
- if (n == NULL)
- {
- // There is no existing session
- // Allow through only SYN packet
- if ((tcp->Flag & TCP_SYN) && ((tcp->Flag & TCP_ACK) == false))
- {
- TCP_OPTION o;
- // Create a new session
- n = CreateNatTcp(v, src_ip, src_port, dest_ip, dest_port);
- if (n == NULL)
- {
- // Return the RST if it was not possible to create
- SendTcp(v, dest_ip, dest_port, src_ip, src_port,
- 0, seq + 1, TCP_RST | TCP_ACK, 0, 0, NULL, 0);
- return;
- }
- // Get the options
- ParseTcpOption(&o, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
- if (o.MaxSegmentSize == 0)
- {
- o.MaxSegmentSize = v->TcpMss;
- }
- Debug("TCP SYN: MSS=%u, WS=%u\n", o.MaxSegmentSize, o.WindowScaling);
- // Initial sequence number
- n->RecvSeqInit = (UINT64)Endian32(tcp->SeqNumber);
- n->RecvSeq = 1;
- n->TcpSendMaxSegmentSize = o.MaxSegmentSize;
- n->TcpRecvWindowSize = NAT_TCP_RECV_WINDOW_SIZE;
- n->TcpSendWindowSize = (UINT)Endian16(tcp->WindowSize);
- if (o.WindowScaling != 0)
- {
- if (o.WindowScaling > 14)
- {
- o.WindowScaling = 14;
- }
- n->TcpSendWindowSize = (n->TcpSendWindowSize << o.WindowScaling);
- }
- }
- }
- if (n == NULL)
- {
- // Return a RST since a packet which is not registered in the NAT entry arrived
- SendTcp(v, dest_ip, dest_port, src_ip, src_port,
- ack, ack, TCP_RST, 0, 0, NULL, 0);
- return;
- }
- n->TcpLastRecvAckTime = v->Now;
- switch (n->TcpStatus)
- {
- case NAT_TCP_SEND_RESET: // Disconnect the connection by sending a RST
- if ((tcp->Flag & TCP_ACK) && ((tcp->Flag & TCP_SYN) == false))
- {
- if (n->FinSentCount >= 1)
- {
- if (ack == (n->FinSentSeq + 1))
- {
- n->TcpForceReset = true;
- }
- }
- }
- break;
- case NAT_TCP_CONNECTED: // Socket connection completion: SYN + ACK, ACK processing
- if ((tcp->Flag & TCP_ACK) && ((tcp->Flag & TCP_SYN) == false))
- {
- if (seq == (UINT)(n->RecvSeqInit + n->RecvSeq) &&
- ack == (UINT)(n->SendSeqInit + n->SendSeq + 1))
- {
- // Handshake complete since the ACK packet came back
- n->SendSeq++; // SYN packet consumes the seq by 1
- Debug("TCP Connection Established.\n");
- n->TcpStatus = NAT_TCP_ESTABLISHED;
- // Initialize the congestion window size
- n->TcpSendCWnd = 1;
- n->LastCommTime = v->Now;
- }
- else
- {
- goto TCP_RESET;
- }
- }
- else if (tcp->Flag & TCP_RST)
- {
- TCP_RESET:
- // Receive a RST
- Debug("TCP Connection Reseted.\n");
- n->TcpStatus = NAT_TCP_SEND_RESET;
- }
- break;
- case NAT_TCP_ESTABLISHED: // Connection established
- if (tcp->Flag & TCP_FIN)
- {
- // Complete the connection
- n->TcpFinished = true;
- }
- if (tcp->Flag & TCP_RST)
- {
- // Receive a RST
- goto TCP_RESET;
- }
- else if (tcp->Flag & TCP_ACK)
- {
- TCP_OPTION opt;
- n->LastCommTime = v->Now;
- // Get the options, such as window size
- n->TcpSendWindowSize = Endian16(tcp->WindowSize);
- ParseTcpOption(&opt, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
- if (opt.WindowScaling != 0)
- {
- if (opt.WindowScaling > 14)
- {
- opt.WindowScaling = 14;
- }
- n->TcpSendWindowSize = (n->TcpSendWindowSize << opt.WindowScaling);
- }
- // First, process the received ACK
- // Store the end position of the stream that has received the acknowledgment to ack64
- ack64 = n->SendSeq + (UINT64)ack - (n->SendSeqInit + n->SendSeq) % X32;
- if ((n->SendSeqInit + n->SendSeq) % X32 > ack)
- {
- if (((n->SendSeqInit + n->SendSeq) % X32 - ack) >= 0x80000000)
- {
- ack64 = n->SendSeq + (UINT64)ack + X32 - (n->SendSeqInit + n->SendSeq) % X32;
- }
- }
- if (ack64 > n->SendSeq)
- {
- // Reception of 1 byte or more seems to have been completed by the client
- UINT slide_offset = (UINT)(ack64 - n->SendSeq); // Sliding size of the window
- if (slide_offset == 0 || slide_offset > n->TcpSendWindowSize || slide_offset > n->SendFifo->size)
- {
- // Ignore because the offset value of acknowledgment is
- // larger than the size that should have been sent so far
- }
- else
- {
- // RTT measurement
- if (n->CalcRTTStartTime != 0)
- {
- if (n->CalcRTTStartValue < ack64)
- {
- UINT time_span;
- if (v->Now > n->CalcRTTStartTime)
- {
- time_span = (UINT)(v->Now - n->CalcRTTStartTime);
- }
- else
- {
- time_span = 100;
- }
- n->CalcRTTStartTime = 0;
- // Smoothing
- n->CurrentRTT =
- (UINT)
- (
- ((UINT64)n->CurrentRTT * (UINT64)9 +
- (UINT64)time_span * (UINT64)1) / (UINT64)10
- );
- n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
- }
- }
- // Reduce the transmission size
- n->SendMissionSize -= slide_offset;
- if (n->SendMissionSize == 0)
- {
- // Try to increase the transmission segment size because
- // all segments to be sent this time have been sent
- if (n->TcpSendCWnd < 65536)
- {
- n->TcpSendCWnd++;
- }
- n->CurrentSendingMission = false;
- n->TcpLastSentTime = 0;
- n->RetransmissionUsedFlag = false;
- }
- // Slide the buffer
- n->SendSeq += slide_offset;
- ReadFifo(n->SendFifo, NULL, slide_offset);
- // Send further by the size of confirmed transmission completion by the ACK this time
- if (n->SendMissionSize != 0 && false)
- {
- UINT notice_window_size_value = 0;
- UINT send_data_size;
- UINT buf_free_bytes;
- UINT send_offset = n->SendMissionSize;
- // Determine the value of the window size to be notified
- if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
- {
- buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
- }
- notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
- // Calculate the segment size to be transmitted
- send_data_size = n->TcpSendWindowSize;
- if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
- {
- // Apply the cwnd value
- send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
- }
- if (n->SendFifo->size > send_offset)
- {
- send_data_size = MIN(send_data_size, n->SendFifo->size - send_offset);
- send_data_size = MIN(send_data_size, slide_offset);
- }
- else
- {
- send_data_size = 0;
- }
- if (send_data_size >= 1)
- {
- // Transmit the fragmented segments
- UINT current_pointer = 0;
- while (send_data_size > 0)
- {
- UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
- void *send_segment = (void *)((
- (UCHAR *)n->SendFifo->p) + n->SendFifo->pos +
- current_pointer + send_offset);
- SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
- (UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer
- + (UINT)send_offset),
- (UINT)(n->RecvSeqInit + n->RecvSeq),
- TCP_ACK | TCP_PSH,
- notice_window_size_value,
- 0,
- send_segment,
- send_segment_size);
- current_pointer += send_segment_size;
- send_data_size -= send_segment_size;
- }
- n->SendMissionSize += current_pointer;
- n->CurrentSendingMission = true;
- n->TcpLastSentTime = v->Now;
- // RTT measurement
- if (n->CalcRTTStartTime == 0)
- {
- n->CalcRTTStartTime = v->Now;
- n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
- }
- }
- }
- // Event occurs
- SetSockEvent(v->SockEvent);
- }
- }
- // Next, receive the data
- seq64 = n->RecvSeq + (UINT64)seq - (n->RecvSeqInit + n->RecvSeq) % X32;
- if ((n->RecvSeqInit + n->RecvSeq) % X32 > seq)
- {
- if (((n->RecvSeqInit + n->RecvSeq) % X32 - ack) >= 0x80000000)
- {
- seq64 = n->RecvSeq + (UINT64)seq + X32 - (n->RecvSeqInit + n->RecvSeq) % X32;
- }
- }
- // Position of the starting point of the data from the client is in the seq64 at this time
- if (seq64 >= n->RecvSeq && (seq64 + size) <= (n->RecvSeq + n->TcpRecvWindowSize))
- {
- if (size >= 1)
- {
- // One or more bytes of data has been received within the receive window
- UINT offset = (UINT)(seq64 - n->RecvSeq);
- UINT i;
- IP_PART *me;
- if (n->TcpRecvWindow == NULL)
- {
- n->TcpRecvWindow = NewFifo();
- }
- if (n->TcpRecvList == NULL)
- {
- n->TcpRecvList = NewListFast(NULL);
- }
- // Add to the list by overwriting arriving packets to the buffer
- if (FifoSize(n->TcpRecvWindow) < (offset + size))
- {
- // Buffer size expansion
- WriteFifo(n->TcpRecvWindow, NULL, offset + size - FifoSize(n->TcpRecvWindow));
- }
- Copy(((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos +
- offset, data, size);
- me = ZeroMalloc(sizeof(IP_PART));
- me->Offset = offset;
- me->Size = size;
- for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
- {
- IP_PART *p = LIST_DATA(n->TcpRecvList, i);
- // If there are overlapped region, remove these
- if (p->Size != 0)
- {
- if (me->Offset <= p->Offset && (me->Offset + me->Size) >= (p->Offset + p->Size))
- {
- // This packet completely overwrite the existing packet
- p->Size = 0;
- }
- else if (me->Offset >= p->Offset && (me->Offset + me->Size) <= (p->Offset + p->Size))
- {
- // Existing packet completely override this packet
- me->Size = 0;
- }
- else if (me->Offset > p->Offset && me->Offset < (p->Offset + p->Size) &&
- (me->Offset + me->Size) > (p->Offset + p->Size))
- {
- // Partially overlapped
- p->Size -= p->Offset + p->Size - me->Offset;
- }
- else if (me->Offset < p->Offset && (me->Offset + size) > p->Offset && (me->Offset + size) < (p->Offset + p->Size))
- {
- // Partially overlapped
- me->Size -= me->Offset + me->Size - p->Offset;
- }
- }
- }
- if (me->Size == 0)
- {
- Free(me);
- }
- else
- {
- Add(n->TcpRecvList, me);
- }
- KILL_NULL_FIRST:
- // Remove all blank items from reception list
- for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
- {
- IP_PART *p = LIST_DATA(n->TcpRecvList, i);
- if (p->Size == 0)
- {
- Delete(n->TcpRecvList, p);
- Free(p);
- goto KILL_NULL_FIRST;
- }
- }
- SCAN_FIRST:
- // Extract if there is something starting at offset 0 in the received list
- for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
- {
- IP_PART *p = LIST_DATA(n->TcpRecvList, i);
- UINT sz;
- if (p->Offset == 0)
- {
- // Since a data block starts with 0 is found,
- // slide it left by that amount and write the buffer
- // for extracting data to the FIFO
- sz = p->Size;
- WriteFifo(n->RecvFifo, ((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos, sz);
- // Release from the list
- Delete(n->TcpRecvList, p);
- Free(p);
- ReadFifo(n->TcpRecvWindow, NULL, sz);
- // Slide all the items to the left
- for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
- {
- p = LIST_DATA(n->TcpRecvList, i);
- p->Offset -= sz;
- }
- // Update the parameters of the TCB
- n->RecvSeq += (UINT64)sz;
- SetSockEvent(v->SockEvent);
- n->SendAckNext = true;
- // Re-scan from the beginning
- goto SCAN_FIRST;
- }
- }
- }
- }
- }
- break;
- }
- SetSockEvent(v->SockEvent);
- }
- // Parse the TCP options
- void ParseTcpOption(TCP_OPTION *o, void *data, UINT size)
- {
- UCHAR *buf = (UCHAR *)data;
- UINT i;
- UINT value_size = 0;
- UINT value_id = 0;
- UCHAR value[128];
- // Validate arguments
- if (o == NULL || data == NULL)
- {
- return;
- }
- Zero(o, sizeof(TCP_OPTION));
- for (i = 0;i < size;i++)
- {
- if (buf[i] == 0)
- {
- return;
- }
- if (buf[i] != 1)
- {
- value_id = buf[i];
- i++;
- if (i >= size)
- {
- return;
- }
- value_size = buf[i];
- if (value_size <= 1 || value_size > sizeof(value))
- {
- return;
- }
- i++;
- if (i >= size)
- {
- return;
- }
- value_size -= 2;
- Copy(value, &buf[i], value_size);
- i += value_size;
- if (i >= size)
- {
- return;
- }
- switch (value_id)
- {
- case 2: // MSS
- if (value_size == 2)
- {
- USHORT *mss = (USHORT *)value;
- o->MaxSegmentSize = Endian16(*mss);
- }
- break;
- case 3: // WSS
- if (value_size == 1)
- {
- UCHAR *wss = (UCHAR *)value;
- o->WindowScaling = Endian16(*wss);
- }
- break;
- }
- }
- }
- }
- // Create a new NAT TCP session
- NAT_ENTRY *CreateNatTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port)
- {
- NAT_ENTRY *n;
- HUB_OPTION *o;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- if (CanCreateNewNatEntry(v) == false)
- {
- return NULL;
- }
- o = NatGetHubOption(v);
- // Fail immediately if the connection with SYN_SENT are too many
- if (o != NULL && o->SecureNAT_MaxTcpSynSentPerIp != 0)
- {
- if (GetNumNatEntriesPerIp(v, src_ip, NAT_TCP, true) >= o->SecureNAT_MaxTcpSynSentPerIp)
- {
- return NULL;
- }
- }
- // If the connections other than SYN_SENT are too many, delete old ones
- if (o != NULL && o->SecureNAT_MaxTcpSessionsPerIp != 0)
- {
- if (GetNumNatEntriesPerIp(v, src_ip, NAT_TCP, false) >= o->SecureNAT_MaxTcpSessionsPerIp)
- {
- NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_TCP);
- if (oldest != NULL)
- {
- DisconnectNatEntryNow(v, oldest);
- }
- }
- }
- // Create a NAT entry
- n = ZeroMalloc(sizeof(NAT_ENTRY));
- n->Id = Inc(v->Counter);
- n->v = v;
- n->lock = NewLock();
- n->Protocol = NAT_TCP;
- n->SrcIp = src_ip;
- n->SrcPort = src_port;
- n->DestIp = dest_ip;
- n->DestPort = dest_port;
- n->CreatedTime = n->LastCommTime = v->Now;
- n->TcpLastRecvAckTime = v->Now;
- n->Sock = NULL;
- n->DisconnectNow = false;
- n->TcpSendMaxSegmentSize = n->TcpRecvMaxSegmentSize = v->TcpMss;
- n->SendFifo = NewFifo();
- n->RecvFifo = NewFifo();
- n->TcpStatus = NAT_TCP_CONNECTING;
- n->SendSeqInit = Rand32();
- n->CurrentRTT = NAT_INITIAL_RTT_VALUE;
- n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
- // Add to the NAT table
- Add(v->NatTable, n);
- #if 1
- {
- IP ip1, ip2;
- char s1[MAX_SIZE], s2[MAX_SIZE];
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- IPToStr(s1, 0, &ip1);
- IPToStr(s2, 0, &ip2);
- Debug("NAT_ENTRY: CreateNatTcp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
- NLog(v, "LH_NAT_TCP_CREATED", n->Id, s1, src_port, s2, dest_port);
- }
- #endif
- return n;
- }
- // Received TCP packets from the virtual network
- void VirtualTcpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UINT max_l3_size)
- {
- TCP_HEADER *tcp;
- UINT src_port, dest_port;
- UINT header_size, buf_size;
- void *buf;
- IP ip1, ip2;
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return;
- }
- // Get the header
- if (size < TCP_HEADER_SIZE)
- {
- // Size is too small
- return;
- }
- tcp = (TCP_HEADER *)data;
- src_port = Endian16(tcp->SrcPort);
- dest_port = Endian16(tcp->DstPort);
- if (src_port == 0 || dest_port == 0)
- {
- // Port number is invalid
- return;
- }
- if (src_ip == dest_ip || src_ip == 0 || src_ip == 0xffffffff || dest_ip == 0 || dest_ip == 0xffffffff)
- {
- // IP address is invalid
- return;
- }
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- if (ip1.addr[0] == 127 || ip2.addr[0] == 127)
- {
- // Loopback IP address can not be specified
- return;
- }
- if (IsInNetwork(dest_ip, v->HostIP, v->HostMask))
- {
- // Ignore the packets toward the network of the virtual LAN side
- return;
- }
- // Get the header size
- header_size = TCP_GET_HEADER_SIZE(tcp) * 4;
- if (size < header_size)
- {
- // Header size is invalid
- return;
- }
- // Get the address and size of the buffer
- buf_size = size - header_size;
- buf = (void *)(((UCHAR *)data) + header_size);
- TcpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, tcp, buf, buf_size, max_l3_size);
- }
- // NAT ICMP polling
- void PollingNatIcmp(VH *v, NAT_ENTRY *n)
- {
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- // Process if there are any packets in the receive queue
- if (n->UdpRecvQueue->num_item != 0)
- {
- BLOCK *block;
- // Send all ICMP packets to the virtual network
- while (block = GetNext(n->UdpRecvQueue))
- {
- // Rewrite the destination IP address of the returned packet to the IP address of the client
- UCHAR *data;
- UINT size;
- data = (UCHAR *)block->Buf;
- size = block->Size;
- if (size >= sizeof(IPV4_HEADER))
- {
- IPV4_HEADER *ipv4 = (IPV4_HEADER *)data;
- UINT ipv4_header_size = GetIpHeaderSize((UCHAR *)ipv4, size);
- if (ipv4_header_size >= sizeof(IPV4_HEADER) && (Endian16(ipv4->TotalLength) >= ipv4_header_size))
- {
- UCHAR *ipv4_payload = data + ipv4_header_size;
- UINT ipv4_payload_size = Endian16(ipv4->TotalLength) - ipv4_header_size;
- if (ipv4_payload_size >= sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO))
- {
- ICMP_HEADER *icmp = (ICMP_HEADER *)(data + ipv4_header_size);
- UINT icmp_size = ipv4_payload_size;
- if (icmp->Type == ICMP_TYPE_DESTINATION_UNREACHABLE || icmp->Type == ICMP_TYPE_TIME_EXCEEDED)
- {
- // Rewrite the Src IP of the IPv4 header of the ICMP response packet
- if (icmp_size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + sizeof(IPV4_HEADER)))
- {
- IPV4_HEADER *orig_ipv4 = (IPV4_HEADER *)(data + ipv4_header_size + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- UINT orig_ipv4_size = icmp_size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
- UINT orig_ipv4_header_size = GetIpHeaderSize((UCHAR *)orig_ipv4, orig_ipv4_size);
- if (orig_ipv4_header_size >= sizeof(IPV4_HEADER))
- {
- orig_ipv4->SrcIP = n->SrcIp;
- orig_ipv4->Checksum = 0;
- orig_ipv4->Checksum = IpChecksum(orig_ipv4, orig_ipv4_header_size);
- }
- }
- }
- // Recalculate the checksum of ICMP
- icmp->Checksum = IpChecksum(icmp, icmp_size);
- SendIpEx(v, n->SrcIp, ipv4->SrcIP, ipv4->Protocol, ipv4_payload, ipv4_payload_size,
- MAX(ipv4->TimeToLive - 1, 1));
- }
- }
- }
- FreeBlock(block);
- }
- if (v->IcmpRawSocketOk == false)
- {
- // Release the NAT entry as soon as the results is received in the case of using ICMP API
- n->DisconnectNow = true;
- }
- }
- }
- // NAT UDP polling
- void PoolingNatUdp(VH *v, NAT_ENTRY *n)
- {
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- // Process if there are any packets in the receive queue
- if (n->UdpRecvQueue->num_item != 0)
- {
- BLOCK *block;
- // Send all UDP packets to the virtual network
- while (block = GetNext(n->UdpRecvQueue))
- {
- UINT src_ip = n->DestIp;
- if (src_ip == 0xFFFFFFFF)
- {
- src_ip = v->HostIP;
- }
- if (block->Param1 != 0)
- {
- src_ip = block->Param1;
- }
- SendUdp(v, n->SrcIp, n->SrcPort, src_ip, n->DestPort,
- block->Buf, block->Size);
- FreeBlock(block);
- }
- }
- }
- // NAT polling
- void PoolingNat(VH *v)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- if (NnIsActive(v))
- {
- // Poll whether the packet comes from native NAT
- NnPoll(v->NativeNat);
- }
- // Process by scanning the all NAT entries
- for (i = 0;i < LIST_NUM(v->NatTable);i++)
- {
- NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
- switch (n->Protocol)
- {
- case NAT_TCP:
- PollingNatTcp(v, n);
- break;
- case NAT_UDP:
- PoolingNatUdp(v, n);
- break;
- case NAT_ICMP:
- PollingNatIcmp(v, n);
- break;
- case NAT_DNS:
- PollingNatDns(v, n);
- break;
- }
- }
- }
- // Comparison function of the NAT table entry
- int CompareNat(void *p1, void *p2)
- {
- NAT_ENTRY *n1, *n2;
- if (p1 == NULL || p2 == NULL)
- {
- return 0;
- }
- n1 = *(NAT_ENTRY **)p1;
- n2 = *(NAT_ENTRY **)p2;
- if (n1 == n2)
- {
- return 0;
- }
- if (n1->SrcIp > n2->SrcIp) return 1;
- else if (n1->SrcIp < n2->SrcIp) return -1;
- else if (n1->DestIp > n2->DestIp) return 1;
- else if (n1->DestIp < n2->DestIp) return -1;
- else if (n1->SrcPort > n2->SrcPort) return 1;
- else if (n1->SrcPort < n2->SrcPort) return -1;
- else if (n1->DestPort > n2->DestPort) return 1;
- else if (n1->DestPort < n2->DestPort) return -1;
- else if (n1->Protocol > n2->Protocol) return 1;
- else if (n1->Protocol < n2->Protocol) return -1;
- else return 0;
- }
- // Configure the NAT structure
- void SetNat(NAT_ENTRY *n, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT public_ip, UINT public_port)
- {
- // Validate arguments
- if (n == NULL)
- {
- return;
- }
- n->Protocol = protocol;
- n->SrcIp = src_ip;
- n->SrcPort = src_port;
- n->DestIp = dest_ip;
- n->DestPort = dest_port;
- n->PublicIp = public_ip;
- n->PublicPort = public_port;
- }
- // Initialize the NAT
- void InitNat(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Create a NAT table
- v->NatTable = NewList(CompareNat);
- // Create a socket event
- v->SockEvent = NewSockEvent();
- // Create the NAT thread
- v->HaltNat = false;
- v->NatThread = NewThread(NatThread, (void *)v);
- WaitThreadInit(v->NatThread);
- if (IsEthSupported())
- {
- // Start a native NAT if access to the layer 2 Ethernet is supported
- v->NativeNat = NewNativeNat(v);
- }
- }
- // Release the NAT
- void FreeNat(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Stop the native NAT
- if (v->NativeNat != NULL)
- {
- FreeNativeNat(v->NativeNat);
- v->NativeNat = NULL;
- }
- // Stop the NAT thread
- v->HaltNat = true;
- SetSockEvent(v->SockEvent);
- WaitThread(v->NatThread, INFINITE);
- ReleaseThread(v->NatThread);
- v->NatThread = NULL;
- ReleaseSockEvent(v->SockEvent);
- v->SockEvent = NULL;
- // Release the NAT table
- ReleaseList(v->NatTable);
- }
- // Search the NAT table
- NAT_ENTRY *SearchNat(VH *v, NAT_ENTRY *target)
- {
- NAT_ENTRY *n;
- // Validate arguments
- if (v == NULL || target == NULL)
- {
- return NULL;
- }
- // Binary search
- n = (NAT_ENTRY *)Search(v->NatTable, target);
- return n;
- }
- // Delete the UDP NAT entry
- void DeleteNatUdp(VH *v, NAT_ENTRY *n)
- {
- BLOCK *block;
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- NLog(v, "LH_NAT_UDP_DELETED", n->Id);
- // Release all queues
- while (block = GetNext(n->UdpRecvQueue))
- {
- FreeBlock(block);
- }
- ReleaseQueue(n->UdpRecvQueue);
- while (block = GetNext(n->UdpSendQueue))
- {
- FreeBlock(block);
- }
- ReleaseQueue(n->UdpSendQueue);
- // Release the socket
- if (n->Sock != NULL)
- {
- Disconnect(n->Sock);
- ReleaseSock(n->Sock);
- n->Sock = NULL;
- }
- DeleteLock(n->lock);
- // Remove from the table
- Delete(v->NatTable, n);
- // Release the memory
- Free(n);
- Debug("NAT: DeleteNatUdp\n");
- }
- // Delete the ICMP NAT entry
- void DeleteNatIcmp(VH *v, NAT_ENTRY *n)
- {
- BLOCK *block;
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- //NLog(v, "LH_NAT_ICMP_DELETED", n->Id);
- // Release all queues
- while (block = GetNext(n->UdpRecvQueue))
- {
- FreeBlock(block);
- }
- ReleaseQueue(n->UdpRecvQueue);
- while (block = GetNext(n->UdpSendQueue))
- {
- FreeBlock(block);
- }
- ReleaseQueue(n->UdpSendQueue);
- if (n->IcmpQueryBlock != NULL)
- {
- FreeBlock(n->IcmpQueryBlock);
- }
- if (n->IcmpResponseBlock != NULL)
- {
- FreeBlock(n->IcmpResponseBlock);
- }
- if (n->IcmpOriginalCopy != NULL)
- {
- Free(n->IcmpOriginalCopy);
- }
- // Release the socket
- if (n->Sock != NULL)
- {
- Disconnect(n->Sock);
- ReleaseSock(n->Sock);
- n->Sock = NULL;
- }
- DeleteLock(n->lock);
- // Remove from the table
- Delete(v->NatTable, n);
- // Release the memory
- Free(n);
- Debug("NAT: DeleteNatIcmp\n");
- }
- // Create a NAT ICMP entry
- NAT_ENTRY *CreateNatIcmp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UCHAR *original_copy, UINT original_copy_size)
- {
- NAT_ENTRY *n;
- HUB_OPTION *o;
- // Validate arguments
- if (v == NULL || original_copy == NULL || original_copy_size == 0)
- {
- return NULL;
- }
- if (CanCreateNewNatEntry(v) == false)
- {
- return NULL;
- }
- o = NatGetHubOption(v);
- if (o != NULL && o->SecureNAT_MaxIcmpSessionsPerIp != 0)
- {
- if (GetNumNatEntriesPerIp(v, src_ip, NAT_ICMP, false) >= o->SecureNAT_MaxIcmpSessionsPerIp)
- {
- NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_ICMP);
- if (oldest != NULL)
- {
- DisconnectNatEntryNow(v, oldest);
- }
- }
- }
- n = ZeroMalloc(sizeof(NAT_ENTRY));
- n->Id = Inc(v->Counter);
- n->v = v;
- n->lock = NewLock();
- n->Protocol = NAT_ICMP;
- n->SrcIp = src_ip;
- n->SrcPort = src_port;
- n->DestIp = dest_ip;
- n->DestPort = dest_port;
- n->CreatedTime = n->LastCommTime = v->Now;
- n->UdpSendQueue = NewQueue();
- n->UdpRecvQueue = NewQueue();
- n->UdpSocketCreated = false;
- n->IcmpOriginalCopy = Clone(original_copy, original_copy_size);
- n->IcmpOriginalCopySize = original_copy_size;
- SetSockEvent(v->SockEvent);
- #if 1
- {
- IP ip1, ip2;
- char s1[MAX_SIZE], s2[MAX_SIZE];
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- IPToStr(s1, 0, &ip1);
- IPToStr(s2, 0, &ip2);
- Debug("NAT_ENTRY: CreateNatIcmp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
- //NLog(v, "LH_NAT_ICMP_CREATED", n->Id, s1, s2, src_port);
- }
- #endif
- Add(v->NatTable, n);
- return n;
- }
- // Create a NAT UDP entry
- NAT_ENTRY *CreateNatUdp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT dns_proxy_ip)
- {
- NAT_ENTRY *n;
- HUB_OPTION *o;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- if (CanCreateNewNatEntry(v) == false)
- {
- return NULL;
- }
- o = NatGetHubOption(v);
- if (o != NULL && o->SecureNAT_MaxTcpSessionsPerIp != 0)
- {
- if (GetNumNatEntriesPerIp(v, src_ip, NAT_UDP, false) >= o->SecureNAT_MaxUdpSessionsPerIp)
- {
- NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_UDP);
- if (oldest != NULL)
- {
- DisconnectNatEntryNow(v, oldest);
- }
- }
- }
- n = ZeroMalloc(sizeof(NAT_ENTRY));
- n->Id = Inc(v->Counter);
- n->v = v;
- n->lock = NewLock();
- n->Protocol = NAT_UDP;
- n->SrcIp = src_ip;
- n->SrcPort = src_port;
- n->DestIp = dest_ip;
- n->DestPort = dest_port;
- if (dns_proxy_ip != 0)
- {
- n->ProxyDns = true;
- n->DestIpProxy = dns_proxy_ip;
- }
- n->CreatedTime = n->LastCommTime = v->Now;
- n->UdpSendQueue = NewQueue();
- n->UdpRecvQueue = NewQueue();
- n->UdpSocketCreated = false;
- SetSockEvent(v->SockEvent);
- #if 1
- {
- IP ip1, ip2;
- char s1[MAX_SIZE], s2[MAX_SIZE];
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- IPToStr(s1, 0, &ip1);
- IPToStr(s2, 0, &ip2);
- Debug("NAT_ENTRY: CreateNatUdp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
- NLog(v, "LH_NAT_UDP_CREATED", n->Id, s1, src_port, s2, dest_port);
- }
- #endif
- Add(v->NatTable, n);
- return n;
- }
- // Ignore for NetBIOS name registration packet
- bool IsNetbiosRegistrationPacket(UCHAR *buf, UINT size)
- {
- // Validate arguments
- if (buf == NULL || size == 0)
- {
- return false;
- }
- if (size >= 4)
- {
- USHORT us = *((USHORT *)(buf + 2));
- us = Endian16(us);
- if (((us & 0x7800) >> 11) == 5)
- {
- return true;
- }
- }
- return false;
- }
- // Generate the encoded NetBIOS name
- void EncodeNetBiosName(UCHAR *dst, char *src)
- {
- char tmp[17];
- UINT i;
- UINT copy_len;
- UINT wp;
- // Validate arguments
- if (dst == NULL || src == NULL)
- {
- return;
- }
- for (i = 0;i < 16;i++)
- {
- tmp[i] = ' ';
- }
- tmp[16] = 0;
- copy_len = StrLen(src);
- if (copy_len > 16)
- {
- copy_len = 16;
- }
- Copy(tmp, src, StrLen(src));
- wp = 0;
- tmp[15] = 0;
- for (i = 0;i < 16;i++)
- {
- char c = tmp[i];
- char *s = CharToNetBiosStr(c);
- dst[wp++] = s[0];
- dst[wp++] = s[1];
- }
- }
- // Convert the string to NetBIOS characters
- char *CharToNetBiosStr(char c)
- {
- c = ToUpper(c);
- switch (c)
- {
- case '\0': return "AA";
- case 'A': return "EB";
- case 'B': return "EC";
- case 'C': return "ED";
- case 'D': return "EE";
- case 'E': return "EF";
- case 'F': return "EG";
- case 'G': return "EH";
- case 'H': return "EI";
- case 'I': return "EJ";
- case 'J': return "EK";
- case 'K': return "EL";
- case 'L': return "EM";
- case 'M': return "EN";
- case 'N': return "EO";
- case 'O': return "EP";
- case 'P': return "FA";
- case 'Q': return "FB";
- case 'R': return "FC";
- case 'S': return "FD";
- case 'T': return "FE";
- case 'U': return "FF";
- case 'V': return "FG";
- case 'W': return "FH";
- case 'X': return "FI";
- case 'Y': return "FJ";
- case 'Z': return "FK";
- case '0': return "DA";
- case '1': return "DB";
- case '2': return "DC";
- case '3': return "DD";
- case '4': return "DE";
- case '5': return "DF";
- case '6': return "DG";
- case '7': return "DH";
- case '8': return "DI";
- case '9': return "DJ";
- case ' ': return "CA";
- case '!': return "CB";
- case '\"': return "CC";
- case '#': return "CD";
- case '$': return "CE";
- case '%': return "CF";
- case '&': return "CG";
- case '\'': return "CH";
- case '(': return "CI";
- case ')': return "CJ";
- case '*': return "CK";
- case '+': return "CL";
- case ',': return "CM";
- case '-': return "CN";
- case '.': return "CO";
- case '=': return "DN";
- case ':': return "DK";
- case ';': return "DL";
- case '@': return "EA";
- case '^': return "FO";
- case '_': return "FP";
- case '{': return "HL";
- case '}': return "HN";
- case '~': return "HO";
- }
- return "CA";
- }
- // Process if a NetBIOS name resolution packet for the my host name
- bool ProcessNetBiosNameQueryPacketForMyself(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
- {
- BUF *rb;
- USHORT tran_id;
- USHORT flags;
- USHORT num_query;
- USHORT zero1, zero2, zero3;
- UCHAR name_size;
- UCHAR encoded_name[32];
- UCHAR node_type;
- USHORT type, classid;
- UCHAR my_pc_encoded_name[32];
- bool ret = false;
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return false;
- }
- rb = NewBufFromMemory(data, size);
- ReadBuf(rb, &tran_id, sizeof(USHORT));
- ReadBuf(rb, &flags, sizeof(USHORT));
- flags = Endian16(flags);
- ReadBuf(rb, &num_query, sizeof(USHORT));
- num_query = Endian16(num_query);
- ReadBuf(rb, &zero1, sizeof(USHORT));
- ReadBuf(rb, &zero2, sizeof(USHORT));
- ReadBuf(rb, &zero3, sizeof(USHORT));
- ReadBuf(rb, &name_size, 1);
- ReadBuf(rb, encoded_name, 32);
- ReadBuf(rb, &node_type, 1);
- ReadBuf(rb, &type, sizeof(USHORT));
- type = Endian16(type);
- if (ReadBuf(rb, &classid, sizeof(USHORT)) == sizeof(USHORT))
- {
- classid = Endian16(classid);
- if (((flags >> 11) & 0x0F) == 0 &&
- num_query == 1 && name_size == 0x20 &&
- zero1 == 0 && zero2 == 0 && zero3 == 0 && node_type == 0 && type == 0x0020 && classid == 0x0001)
- {
- char my_pcname[MAX_SIZE];
- // Get the encoded name of this PC
- Zero(my_pcname, sizeof(my_pcname));
- GetMachineHostName(my_pcname, sizeof(my_pcname));
- EncodeNetBiosName(my_pc_encoded_name, my_pcname);
- if (Cmp(my_pc_encoded_name, encoded_name, 30) == 0)
- {
- // Assemble the response packet since the name resolution packet which targets this PC name received
- BUF *sb = NewBuf();
- USHORT us;
- UINT ui;
- LIST *ip_list;
- BUF *ip_list_buf;
- bool found = false;
- WriteBuf(sb, &tran_id, sizeof(USHORT));
- flags = Endian16(0x8500);
- WriteBuf(sb, &flags, sizeof(USHORT));
- num_query = 0;
- WriteBuf(sb, &num_query, sizeof(USHORT));
- us = Endian16(1);
- WriteBuf(sb, &us, sizeof(USHORT));
- us = 0;
- WriteBuf(sb, &us, sizeof(USHORT));
- WriteBuf(sb, &us, sizeof(USHORT));
- name_size = 0x20;
- WriteBuf(sb, &name_size, 1);
- WriteBuf(sb, encoded_name, 32);
- node_type = 0;
- WriteBuf(sb, &node_type, 1);
- type = Endian16(type);
- classid = Endian16(classid);
- WriteBuf(sb, &type, sizeof(USHORT));
- WriteBuf(sb, &classid, sizeof(USHORT));
- ui = Endian32((UINT)(Tick64() / 1000ULL));
- WriteBuf(sb, &ui, sizeof(UINT));
- ip_list_buf = NewBuf();
- ip_list = GetHostIPAddressList();
- if (ip_list != NULL)
- {
- UINT i;
- // Return only private IP if there is a private IP
- for (i = 0;i < LIST_NUM(ip_list);i++)
- {
- IP *ip = LIST_DATA(ip_list, i);
- if (IsIP4(ip) && IsLocalHostIP4(ip) == false && IsZeroIp(ip) == false)
- {
- if (IsIPPrivate(ip))
- {
- USHORT flags = Endian16(0x4000);
- UINT ip_uint = IPToUINT(ip);
- WriteBuf(ip_list_buf, &flags, sizeof(USHORT));
- WriteBuf(ip_list_buf, &ip_uint, sizeof(UINT));
- found = true;
- }
- }
- }
- if (found == false)
- {
- // Return all IP if no private IP are found
- for (i = 0;i < LIST_NUM(ip_list);i++)
- {
- IP *ip = LIST_DATA(ip_list, i);
- if (IsIP4(ip) && IsLocalHostIP4(ip) == false && IsZeroIp(ip) == false)
- {
- USHORT flags = Endian16(0x4000);
- UINT ip_uint = IPToUINT(ip);
- WriteBuf(ip_list_buf, &flags, sizeof(USHORT));
- WriteBuf(ip_list_buf, &ip_uint, sizeof(UINT));
- found = true;
- }
- }
- }
- FreeHostIPAddressList(ip_list);
- }
- us = Endian16(ip_list_buf->Size);
- WriteBuf(sb, &us, sizeof(USHORT));
- WriteBufBuf(sb, ip_list_buf);
- SendUdp(v, src_ip, src_port, v->HostIP, dest_port, sb->Buf, sb->Size);
- FreeBuf(ip_list_buf);
- FreeBuf(sb);
- WHERE;
- }
- }
- }
- FreeBuf(rb);
- return ret;
- }
- // Process the NetBIOS broadcast packet
- void UdpRecvForNetBiosBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy, bool unicast)
- {
- // Validate arguments
- if (data == NULL || v == NULL)
- {
- return;
- }
- // Ignore for NetBIOS name registration packet
- if (IsNetbiosRegistrationPacket(data, size) == false)
- {
- if (unicast == false)
- {
- dest_ip = 0xFFFFFFFF;
- }
- if (ProcessNetBiosNameQueryPacketForMyself(v, src_ip, src_port, dest_ip, dest_port, data, size) == false)
- {
- UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, data, size, false);
- }
- }
- }
- // Process the UDP packet to the Internet
- void UdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy)
- {
- NAT_ENTRY *n, t;
- BLOCK *block;
- void *buf;
- UINT dns_ip = 0;
- // Validate arguments
- if (data == NULL || v == NULL)
- {
- return;
- }
- if (dns_proxy)
- {
- // Get the DNS server of the proxy to connect to
- IP ip;
- char tmp[MAX_SIZE];
- if (GetDefaultDns(&ip) == false)
- {
- // Failure
- Debug("Failed to GetDefaultDns()\n");
- return;
- }
- dns_ip = IPToUINT(&ip);
- IPToStr(tmp, sizeof(tmp), &ip);
- Debug("Redirect to DNS Server %s\n", tmp);
- }
- // Examine whether the NAT entry for this packet has already been created
- SetNat(&t, NAT_UDP, src_ip, src_port, dest_ip, dest_port, 0, 0);
- n = SearchNat(v, &t);
- if (n == NULL)
- {
- // Create a NAT entry because it is the first packet
- n = CreateNatUdp(v, src_ip, src_port, dest_ip, dest_port, dns_proxy ? dns_ip : 0);
- if (n == NULL)
- {
- // Entry creation failed
- return;
- }
- if (dns_proxy)
- {
- n->ProxyDns = true;
- n->DestIpProxy = dns_ip;
- }
- }
- // Set the event by inserting the packet into the queue
- buf = Malloc(size);
- Copy(buf, data, size);
- block = NewBlock(buf, size, 0);
- InsertQueue(n->UdpSendQueue, block);
- SetSockEvent(v->SockEvent);
- }
- // Attempt to interpret the DNS packet
- bool ParseDnsPacket(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
- {
- return ParseDnsPacketEx(v, src_ip, src_port, dest_ip, dest_port, data, size, NULL);
- }
- bool ParseDnsPacketEx(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, DNS_PARSED_PACKET *parsed_result)
- {
- DNSV4_HEADER *dns;
- NAT_ENTRY *nat;
- UINT transaction_id;
- void *query_data;
- UINT query_data_size;
- char hostname[256];
- // Validate arguments
- if (v == NULL || data == NULL || size == 0)
- {
- return false;
- }
- // Check the header size
- if (size < sizeof(DNSV4_HEADER))
- {
- // Undersize
- return false;
- }
- // DNS header acquisition
- dns = (DNSV4_HEADER *)data;
- transaction_id = Endian16(dns->TransactionId);
- if ((dns->Flag1 & 78) != 0 || (dns->Flag1 & 0x80) != 0)
- {
- // Illegal opcode
- return false;
- }
- if (Endian16(dns->NumQuery) != 1)
- {
- // Number of queries is invalid
- return false;
- }
- query_data = ((UCHAR *)dns) + sizeof(DNSV4_HEADER);
- query_data_size = size - sizeof(DNSV4_HEADER);
- // Interpret the query
- if (ParseDnsQuery(hostname, sizeof(hostname), query_data, query_data_size) == false)
- {
- // Interpretation fails
- return false;
- }
- if (parsed_result != NULL)
- {
- // Only analyse without processing
- Zero(parsed_result, sizeof(DNS_PARSED_PACKET));
- StrCpy(parsed_result->Hostname, sizeof(parsed_result->Hostname), hostname);
- parsed_result->TransactionId = transaction_id;
- return true;
- }
- // Create a DNS entry
- nat = CreateNatDns(v, src_ip, src_port, dest_ip, dest_port, transaction_id,
- false, hostname);
- if (nat == false)
- {
- return false;
- }
- return true;
- }
- // Send the NAT DNS response packet
- void SendNatDnsResponse(VH *v, NAT_ENTRY *n)
- {
- BUF *b;
- UINT dns_header_size;
- DNSV4_HEADER *dns;
- UINT src_ip;
- // Validate arguments
- if (n == NULL || v == NULL)
- {
- return;
- }
- // Generate the data
- b = NewBuf();
- // Add a Query
- if (n->DnsGetIpFromHost == false)
- {
- BuildDnsQueryPacket(b, n->DnsTargetHostName, false);
- }
- else
- {
- BuildDnsQueryPacket(b, n->DnsTargetHostName, true);
- }
- // Add a Response
- if (n->DnsOk)
- {
- if (n->DnsGetIpFromHost == false)
- {
- BuildDnsResponsePacketA(b, &n->DnsResponseIp);
- }
- else
- {
- BuildDnsResponsePacketPtr(b, n->DnsResponseHostName);
- }
- }
- // Generate a DNS header
- dns_header_size = sizeof(DNSV4_HEADER) + b->Size;
- dns = ZeroMalloc(dns_header_size);
- dns->TransactionId = Endian16((USHORT)n->DnsTransactionId);
- // Generate a response flag
- if (n->DnsOk)
- {
- dns->Flag1 = 0x85;
- dns->Flag2 = 0x80;
- }
- else
- {
- dns->Flag1 = 0x85;
- dns->Flag2 = 0x83;
- }
- dns->NumQuery = Endian16(1);
- dns->AnswerRRs = Endian16(n->DnsOk != false ? 1 : 0);
- dns->AuthorityRRs = 0;
- dns->AdditionalRRs = 0;
- // Settings, such as the source IP address
- src_ip = n->DestIp;
- if (src_ip == Endian32(SPECIAL_IPV4_ADDR_LLMNR_DEST) && n->DestPort == SPECIAL_UDP_PORT_LLMNR)
- {
- // Make a unicast response in the case of LLMNR packet
- src_ip = v->HostIP;
- dns->Flag1 = 0x84;
- dns->Flag2 = 0x00;
- }
- // Copy data
- Copy(((UCHAR *)dns) + sizeof(DNSV4_HEADER), b->Buf, b->Size);
- // Send this packet
- SendUdp(v, n->SrcIp, n->SrcPort, src_ip, n->DestPort, dns, dns_header_size);
- // Release the memory
- Free(dns);
- FreeBuf(b);
- }
- // Generate a DNS response packet (host name)
- void BuildDnsResponsePacketPtr(BUF *b, char *hostname)
- {
- USHORT magic;
- USHORT type, clas;
- UINT ttl;
- USHORT len;
- BUF *c;
- // Validate arguments
- if (b == NULL || hostname == NULL)
- {
- return;
- }
- magic = Endian16(0xc00c);
- type = Endian16(0x000c);
- clas = Endian16(0x0001);
- ttl = Endian32(NAT_DNS_RESPONSE_TTL);
- c = BuildDnsHostName(hostname);
- if (c == NULL)
- {
- return;
- }
- len = Endian16((USHORT)c->Size);
- WriteBuf(b, &magic, 2);
- WriteBuf(b, &type, 2);
- WriteBuf(b, &clas, 2);
- WriteBuf(b, &ttl, 4);
- WriteBuf(b, &len, 2);
- WriteBuf(b, c->Buf, c->Size);
- FreeBuf(c);
- }
- // Generate a DNS response packet (host IP address)
- void BuildDnsResponsePacketA(BUF *b, IP *ip)
- {
- UINT ip_addr;
- USHORT magic;
- USHORT type, clas;
- UINT ttl;
- USHORT len;
- // Validate arguments
- if (b == NULL || ip == NULL)
- {
- return;
- }
- ip_addr = IPToUINT(ip);
- magic = Endian16(0xc00c);
- type = Endian16(0x0001);
- clas = Endian16(0x0001);
- ttl = Endian32(NAT_DNS_RESPONSE_TTL);
- len = Endian16((USHORT)sizeof(ttl));
- WriteBuf(b, &magic, sizeof(magic));
- WriteBuf(b, &type, sizeof(type));
- WriteBuf(b, &clas, sizeof(clas));
- WriteBuf(b, &ttl, sizeof(ttl));
- WriteBuf(b, &len, sizeof(len));
- WriteBuf(b, &ip_addr, sizeof(ip_addr));
- }
- // Generate a DNS query data packet
- void BuildDnsQueryPacket(BUF *b, char *hostname, bool ptr)
- {
- USHORT val;
- BUF *c;
- // Validate arguments
- if (b == NULL || hostname == NULL)
- {
- return;
- }
- // Convert the host name to a buffer
- c = BuildDnsHostName(hostname);
- if (c == NULL)
- {
- return;
- }
- WriteBuf(b, c->Buf, c->Size);
- FreeBuf(c);
- // Type and class
- if (ptr == false)
- {
- val = Endian16(0x0001);
- }
- else
- {
- val = Endian16(0x000c);
- }
- WriteBuf(b, &val, 2);
- val = Endian16(0x0001);
- WriteBuf(b, &val, 2);
- }
- // Generate a DNS host name buffer
- BUF *BuildDnsHostName(char *hostname)
- {
- UINT i;
- UCHAR size;
- TOKEN_LIST *token;
- BUF *b;
- // Validate arguments
- if (hostname == NULL)
- {
- return NULL;
- }
- // Split the host name into tokens
- token = ParseToken(hostname, ".");
- if (token == NULL)
- {
- return NULL;
- }
- b = NewBuf();
- // Add a host string
- for (i = 0;i < token->NumTokens;i++)
- {
- size = (UCHAR)StrLen(token->Token[i]);
- WriteBuf(b, &size, 1);
- WriteBuf(b, token->Token[i], size);
- }
- // NULL character
- size = 0;
- WriteBuf(b, &size, 1);
- SeekBuf(b, 0, 0);
- FreeToken(token);
- return b;
- }
- // Process the NAT DNS entry
- void PollingNatDns(VH *v, NAT_ENTRY *n)
- {
- // Validate arguments
- if (v == NULL || n == NULL)
- {
- return;
- }
- if (n->DnsFinished)
- {
- if (n->DnsPollingFlag == false)
- {
- n->DnsPollingFlag = true;
- // Process has been completed
- SendNatDnsResponse(v, n);
- // Terminating
- n->DisconnectNow = true;
- }
- }
- }
- // Create a NAT DNS entry
- NAT_ENTRY *CreateNatDns(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port,
- UINT transaction_id, bool dns_get_ip_from_host, char *dns_target_host_name)
- {
- NAT_ENTRY *n;
- HUB_OPTION *o;
- // Validate arguments
- if (v == NULL || dns_target_host_name == NULL)
- {
- return NULL;
- }
- if (CanCreateNewNatEntry(v) == false)
- {
- return NULL;
- }
- o = NatGetHubOption(v);
- if (o != NULL && o->SecureNAT_MaxDnsSessionsPerIp != 0)
- {
- if (GetNumNatEntriesPerIp(v, src_ip, NAT_DNS, false) >= o->SecureNAT_MaxDnsSessionsPerIp)
- {
- NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_DNS);
- if (oldest != NULL)
- {
- DisconnectNatEntryNow(v, oldest);
- }
- }
- }
- n = ZeroMalloc(sizeof(NAT_ENTRY));
- n->Id = Inc(v->Counter);
- n->v = v;
- n->lock = NewLock();
- n->Protocol = NAT_DNS;
- n->SrcIp = src_ip;
- n->SrcPort = src_port;
- n->DestIp = dest_ip;
- n->DestPort = dest_port;
- n->DnsTransactionId = transaction_id;
- n->CreatedTime = n->LastCommTime = v->Now;
- n->DisconnectNow = false;
- n->DnsGetIpFromHost = false;
- n->DnsTargetHostName = CopyStr(dns_target_host_name);
- Add(v->NatTable, n);
- #if 1
- {
- IP ip1, ip2;
- char s1[MAX_SIZE], s2[MAX_SIZE];
- UINTToIP(&ip1, src_ip);
- UINTToIP(&ip2, dest_ip);
- IPToStr(s1, 0, &ip1);
- IPToStr(s2, 0, &ip2);
- Debug("NAT_ENTRY: CreateNatDns %s %u -> %s %u\n", s1, src_port, s2, dest_port);
- }
- #endif
- return n;
- }
- // Get the next byte
- UCHAR GetNextByte(BUF *b)
- {
- UCHAR c = 0;
- // Validate arguments
- if (b == NULL)
- {
- return 0;
- }
- if (ReadBuf(b, &c, 1) != 1)
- {
- return 0;
- }
- return c;
- }
- // Interpret the DNS query
- bool ParseDnsQuery(char *name, UINT name_size, void *data, UINT data_size)
- {
- BUF *b;
- char tmp[257];
- bool ok = true;
- USHORT val;
- // Validate arguments
- if (name == NULL || data == NULL || data_size == 0)
- {
- return false;
- }
- StrCpy(name, name_size, "");
- b = NewBuf();
- WriteBuf(b, data, data_size);
- SeekBuf(b, 0, 0);
- while (true)
- {
- UINT next_len = (UINT)GetNextByte(b);
- if (next_len > 0)
- {
- // Read only the specified length
- Zero(tmp, sizeof(tmp));
- if (ReadBuf(b, tmp, next_len) != next_len)
- {
- ok = false;
- break;
- }
- // Append
- if (StrLen(name) != 0)
- {
- StrCat(name, name_size, ".");
- }
- StrCat(name, name_size, tmp);
- }
- else
- {
- // Read all
- break;
- }
- }
- if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
- {
- ok = false;
- }
- else
- {
- if (Endian16(val) != 0x01 && Endian16(val) != 0x0c)
- {
- ok = false;
- }
- }
- if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
- {
- ok = false;
- }
- else
- {
- if (Endian16(val) != 0x01)
- {
- ok = false;
- }
- }
- FreeBuf(b);
- if (ok == false || StrLen(name) == 0)
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- // Set the VGS host name
- void SetDnsProxyVgsHostname(char *hostname)
- {
- // Validate arguments
- if (hostname == NULL)
- {
- return;
- }
- StrCpy(v_vgs_hostname, sizeof(v_vgs_hostname), hostname);
- }
- // Operate as a DNS proxy
- void DnsProxy(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
- {
- // Validate arguments
- if (v == NULL || data == NULL || size == 0)
- {
- return;
- }
- if (dest_port == SPECIAL_UDP_PORT_LLMNR)
- {
- // Process by analyzing the DNS query in the case of LLMNR
- ParseDnsPacket(v, src_ip, src_port, dest_ip, dest_port, data, size);
- }
- else
- {
- // Forward the packet as it is in the case of a normal DNS packet
- if (IsEmptyStr(v_vgs_hostname) == false)
- {
- // Response by proxy in the case of trying to get the IP of the VGS
- DNS_PARSED_PACKET p;
- Zero(&p, sizeof(p));
- if (ParseDnsPacketEx(v, src_ip, src_port, dest_ip, dest_port, data, size, &p))
- {
- if (StrCmpi(p.Hostname, "254.254.211.10.in-addr.arpa") == 0)
- {
- NAT_ENTRY n;
- Zero(&n, sizeof(n));
- n.DnsTargetHostName = p.Hostname;
- n.DnsGetIpFromHost = true;
- n.DnsResponseHostName = v_vgs_hostname;
- n.DnsTransactionId = p.TransactionId;
- n.DnsOk = true;
- n.DestIp = dest_ip;
- n.SrcIp = src_ip;
- n.DestPort = dest_port;
- n.SrcPort = src_port;
- SendNatDnsResponse(v, &n);
- return;
- }
- }
- }
- UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, data, size, true);
- }
- }
- // Process the LLMNR query
- void UdpRecvLlmnr(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
- {
- // Validate arguments
- if (data == NULL || v == NULL)
- {
- return;
- }
- if (dest_port == SPECIAL_UDP_PORT_LLMNR)
- {
- // DNS proxy start
- DnsProxy(v, src_ip, src_port, dest_ip, dest_port, data, size);
- }
- }
- // Process the UDP packet to the virtual host
- void UdpRecvForMe(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
- {
- // Validate arguments
- if (data == NULL || v == NULL)
- {
- return;
- }
- if (dest_port == NAT_DNS_PROXY_PORT)
- {
- // DNS proxy start
- DnsProxy(v, src_ip, src_port, dest_ip, dest_port, data, size);
- }
- }
- // Process the UDP broadcast packet
- void UdpRecvForBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
- {
- // Validate arguments
- if (data == NULL || v == NULL)
- {
- return;
- }
- }
- // An UDP packet has been received
- void VirtualUdpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, bool mac_broadcast, bool is_localmac, UINT max_l3_size)
- {
- UDP_HEADER *udp;
- UINT packet_length;
- void *buf;
- UINT buf_size;
- UINT src_port, dest_port;
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return;
- }
- // Check the header
- udp = (UDP_HEADER *)data;
- if (size < UDP_HEADER_SIZE)
- {
- return;
- }
- packet_length = Endian16(udp->PacketLength);
- if (packet_length != size)
- {
- return;
- }
- buf = ((UCHAR *)data) + UDP_HEADER_SIZE;
- buf_size = size - UDP_HEADER_SIZE;
- src_port = Endian16(udp->SrcPort);
- dest_port = Endian16(udp->DstPort);
- // Check the port number
- if (dest_port == 0)
- {
- // Port number is invalid
- return;
- }
- // Determine whether it's broadcast packet or packet addressed to myself
- if (dest_ip == v->HostIP)
- {
- // IP packet addressed to myself has arrived
- UdpRecvForMe(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
- }
- else if ((mac_broadcast || dest_ip == Endian32(0xE00000FC)) && dest_port == SPECIAL_UDP_PORT_LLMNR)
- {
- if (is_localmac == false)
- {
- // Packet addressed to 224.0.0.252 (LLMNR) arrives
- UdpRecvLlmnr(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
- }
- }
- else if (mac_broadcast && (dest_port == SPECIAL_UDP_PORT_WSD || dest_port == SPECIAL_UDP_PORT_SSDP))
- {
- if (is_localmac == false)
- {
- // WS-Discovery packet arrives
- UdpRecvForInternet(v, src_ip, src_port, 0xFFFFFFFF, dest_port, buf, buf_size, false);
- }
- }
- else if (mac_broadcast && (dest_port == SPECIAL_UDP_PORT_NBTDGM || dest_port == SPECIAL_UDP_PORT_NBTNS))
- {
- if (is_localmac == false)
- {
- // NetBIOS Broadcast packet arrived
- UdpRecvForNetBiosBroadcast(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, false, false);
- }
- }
- else if (mac_broadcast || dest_ip == 0xffffffff || dest_ip == GetBroadcastAddress(v->HostIP, v->HostMask))
- {
- if (is_localmac == false)
- {
- // Broadcast packet arrived
- UdpRecvForBroadcast(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
- }
- }
- else if (IsInNetwork(dest_ip, v->HostIP, v->HostMask) == false)
- {
- // Packets to other than local address (that is on the Internet) has been received
- if (NnIsActive(v) == false)
- {
- if (v->HubOption != NULL && v->HubOption->DisableUserModeSecureNAT)
- {
- // User-mode NAT is disabled
- return;
- }
- // User-mode NAT
- UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, false);
- }
- else
- {
- // Kernel-mode NAT
- NnUdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, max_l3_size);
- }
- }
- else
- {
- // Local address has arrived. Ignore it
- }
- }
- // Determine the network address of the subnet to which the specified IP address belongs
- UINT GetNetworkAddress(UINT addr, UINT mask)
- {
- return (addr & mask);
- }
- // Determine the broadcast address of the subnet to which the specified IP address belongs
- UINT GetBroadcastAddress(UINT addr, UINT mask)
- {
- return ((addr & mask) | (~mask));
- }
- void GetBroadcastAddress4(IP *dst, IP *addr, IP *mask)
- {
- // Validate arguments
- if (dst == NULL || IsIP4(addr) == false || IsIP4(mask) == false)
- {
- Zero(dst, sizeof(IP));
- return;
- }
- UINTToIP(dst, GetBroadcastAddress(IPToUINT(addr), IPToUINT(mask)));
- }
- // Determine whether the specified IP address belongs to the sub-network that is
- // represented by a another specified network address and a subnet mask
- bool IsInNetwork(UINT uni_addr, UINT network_addr, UINT mask)
- {
- if (GetNetworkAddress(uni_addr, mask) == GetNetworkAddress(network_addr, mask))
- {
- return true;
- }
- return false;
- }
- // Send an UDP packet
- void SendUdp(VH *v, UINT dest_ip, UINT dest_port, UINT src_ip, UINT src_port, void *data, UINT size)
- {
- UDPV4_PSEUDO_HEADER *vh;
- UDP_HEADER *udp;
- UINT udp_packet_length = UDP_HEADER_SIZE + size;
- USHORT checksum;
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return;
- }
- if (udp_packet_length > 65536)
- {
- return;
- }
- // Generate a virtual header
- vh = Malloc(sizeof(UDPV4_PSEUDO_HEADER) + size);
- udp = (UDP_HEADER *)(((UCHAR *)vh) + 12);
- vh->SrcIP = src_ip;
- vh->DstIP = dest_ip;
- vh->Reserved = 0;
- vh->Protocol = IP_PROTO_UDP;
- vh->PacketLength1 = Endian16((USHORT)udp_packet_length);
- udp->SrcPort = Endian16((USHORT)src_port);
- udp->DstPort = Endian16((USHORT)dest_port);
- udp->PacketLength = Endian16((USHORT)udp_packet_length);
- udp->Checksum = 0;
- // Copy data
- Copy(((UCHAR *)udp) + UDP_HEADER_SIZE, data, size);
- // Calculate the checksum
- checksum = IpChecksum(vh, udp_packet_length + 12);
- if (checksum == 0x0000)
- {
- checksum = 0xffff;
- }
- udp->Checksum = checksum;
- // Send a packet
- SendIp(v, dest_ip, src_ip, IP_PROTO_UDP, udp, udp_packet_length);
- // Release the memory
- Free(vh);
- }
- // Poll the IP combining object
- void PollingIpCombine(VH *v)
- {
- LIST *o;
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Discard the old combining object
- o = NULL;
- for (i = 0;i < LIST_NUM(v->IpCombine);i++)
- {
- IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
- if (c->Expire < v->Now)
- {
- if (o == NULL)
- {
- o = NewListFast(NULL);
- }
- Add(o, c);
- }
- }
- if (o != NULL)
- {
- for (i = 0;i < LIST_NUM(o);i++)
- {
- IP_COMBINE *c = LIST_DATA(o, i);
- // Remove from the list
- Delete(v->IpCombine, c);
- // Release the memory
- FreeIpCombine(v, c);
- }
- ReleaseList(o);
- }
- }
- // Send an ICMP packet
- void VirtualIcmpSend(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
- {
- ICMP_HEADER *icmp;
- void *data_buf;
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return;
- }
- // Build the header
- icmp = ZeroMalloc(sizeof(ICMP_HEADER) + size);
- // Data copy
- data_buf = ((UCHAR *)icmp) + sizeof(ICMP_HEADER);
- Copy(data_buf, data, size);
- // Other
- icmp->Checksum = 0;
- icmp->Code = 0;
- icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
- // Checksum
- icmp->Checksum = IpChecksum(icmp, sizeof(ICMP_HEADER) + size);
- // IP packet transmission
- SendIp(v, dst_ip, src_ip, IP_PROTO_ICMPV4, icmp, sizeof(ICMP_HEADER) + size);
- // Release the memory
- Free(icmp);
- }
- // Send the ICMP Echo Response packet
- void VirtualIcmpEchoSendResponse(VH *v, UINT src_ip, UINT dst_ip, USHORT id, USHORT seq_no, void *data, UINT size)
- {
- ICMP_ECHO *e;
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return;
- }
- // Build the header
- e = ZeroMalloc(sizeof(ICMP_ECHO) + size);
- e->Identifier = Endian16(id);
- e->SeqNo = Endian16(seq_no);
- // Data copy
- Copy(((UCHAR *)e) + sizeof(ICMP_ECHO), data, size);
- // Send an ICMP
- VirtualIcmpSend(v, src_ip, dst_ip, e, sizeof(ICMP_ECHO) + size);
- // Release the memory
- Free(e);
- }
- // Treat the ICMP Echo Request packet with a Raw Socket
- void VirtualIcmpEchoRequestReceivedRaw(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size)
- {
- ICMP_ECHO *echo;
- UINT data_size;
- void *data_buf;
- USHORT id, seq_no;
- void *buf;
- BLOCK *block;
- // Validate arguments
- if (v == NULL || data == NULL || icmp_data == NULL || ip_header == NULL)
- {
- return;
- }
- if (ttl == 0)
- {
- ttl = 1;
- }
- echo = (ICMP_ECHO *)data;
- // Echo size check
- if (size < sizeof(ICMP_ECHO))
- {
- // Insufficient data
- return;
- }
- id = Endian16(echo->Identifier);
- seq_no = Endian16(echo->SeqNo);
- // Data size
- data_size = size - sizeof(ICMP_ECHO);
- // Data body
- data_buf = ((UCHAR *)data) + sizeof(ICMP_ECHO);
- if (dst_ip == v->HostIP)
- {
- // Respond because it is addressed to me
- VirtualIcmpEchoSendResponse(v, v->HostIP, src_ip, id, seq_no, data_buf, data_size);
- }
- else if (IsInNetwork(dst_ip, v->HostIP, v->HostMask) == false)
- {
- NAT_ENTRY *n = NULL, t;
- // Process by creating a NAT entry because it is addressed to the Internet
- if (ttl <= 1)
- {
- // Reply the Time Exceeded immediately for the packet whose TTL is 1
- UINT reply_size = sizeof(ICMP_HEADER) + 4 + ip_header_size + 8;
- UCHAR *reply_data = ZeroMalloc(reply_size);
- ICMP_HEADER *icmp = (ICMP_HEADER *)reply_data;
- icmp->Type = ICMP_TYPE_TIME_EXCEEDED;
- icmp->Code = ICMP_CODE_TTL_EXCEEDED_IN_TRANSIT;
- Copy(reply_data + sizeof(ICMP_HEADER) + 4, ip_header, ip_header_size);
- Copy(reply_data + sizeof(ICMP_HEADER) + 4 + ip_header_size, icmp_data, MIN(icmp_size, 8));
- icmp->Checksum = IpChecksum(icmp, reply_size);
- SendIp(v, src_ip, v->HostIP, IP_PROTO_ICMPV4, reply_data, reply_size);
- Free(reply_data);
- }
- else
- {
- SetNat(&t, NAT_ICMP, src_ip, id, dst_ip, id, 0, 0);
- if (v->IcmpRawSocketOk)
- {
- // Examine whether a NAT entry for this packet has already been created
- n = SearchNat(v, &t);
- }
- if (n == NULL)
- {
- // Create a NAT entry because it is the first packet
- n = CreateNatIcmp(v, src_ip, id, dst_ip, id, (UCHAR *)ip_header, ip_header_size + 8);
- if (n == NULL)
- {
- // Entry creation failed
- return;
- }
- }
- // Set the event by inserting the packet into the queue
- buf = Malloc(icmp_size);
- Copy(buf, icmp_data, icmp_size);
- block = NewBlock(buf, icmp_size, 0);
- block->Ttl = MAKESURE(ttl - 1, 1, 255);
- InsertQueue(n->UdpSendQueue, block);
- SetSockEvent(v->SockEvent);
- }
- }
- }
- // Receive an ICMP Echo Request packet
- void VirtualIcmpEchoRequestReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
- {
- ICMP_ECHO *echo;
- UINT data_size;
- void *data_buf;
- USHORT id, seq_no;
- // Validate arguments
- if (v == NULL || data == NULL || icmp_data == NULL)
- {
- return;
- }
- if (NnIsActive(v))
- {
- // Process by the Native NAT
- NnIcmpEchoRecvForInternet(v, src_ip, dst_ip, data, size, ttl, icmp_data, icmp_size,
- ip_header, ip_header_size, max_l3_size);
- return;
- }
- if (v->HubOption != NULL && v->HubOption->DisableUserModeSecureNAT)
- {
- // User-mode NAT is disabled
- return;
- }
- if (v->IcmpRawSocketOk || v->IcmpApiOk)
- {
- // Process in the Raw Socket
- VirtualIcmpEchoRequestReceivedRaw(v, src_ip, dst_ip, data, size, ttl, icmp_data, icmp_size,
- ip_header, ip_header_size);
- return;
- }
- // Returns the fake ICMP forcibly if any of Native NAT or Raw Socket can not be used
- echo = (ICMP_ECHO *)data;
- // Echo size check
- if (size < sizeof(ICMP_ECHO))
- {
- // Insufficient data
- return;
- }
- id = Endian16(echo->Identifier);
- seq_no = Endian16(echo->SeqNo);
- // Data size
- data_size = size - sizeof(ICMP_ECHO);
- // Data body
- data_buf = ((UCHAR *)data) + sizeof(ICMP_ECHO);
- // Return the ICMP Echo Response
- VirtualIcmpEchoSendResponse(v, dst_ip, src_ip, id, seq_no, data_buf, data_size);
- }
- // An ICMP packet has been received
- void VirtualIcmpReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
- {
- ICMP_HEADER *icmp;
- UINT msg_size;
- USHORT checksum_calc, checksum_original;
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return;
- }
- // Size check
- if (size < sizeof(ICMP_HEADER))
- {
- return;
- }
- // ICMP header
- icmp = (ICMP_HEADER *)data;
- // Get the ICMP message size
- msg_size = size - sizeof(ICMP_HEADER);
- // Check the checksum of the ICMP header
- checksum_original = icmp->Checksum;
- icmp->Checksum = 0;
- checksum_calc = IpChecksum(data, size);
- icmp->Checksum = checksum_original;
- if (checksum_calc != checksum_original)
- {
- // Checksum is invalid
- Debug("ICMP CheckSum Failed.\n");
- return;
- }
- // Identified by the opcode
- switch (icmp->Type)
- {
- case ICMP_TYPE_ECHO_REQUEST: // ICMP Echo request
- VirtualIcmpEchoRequestReceived(v, src_ip, dst_ip, ((UCHAR *)data) + sizeof(ICMP_HEADER), msg_size, ttl,
- icmp, size, ip_header, ip_header_size, max_l3_size);
- break;
- case ICMP_TYPE_ECHO_RESPONSE: // ICMP Echo response
- // Do Nothing
- break;
- }
- }
- // Received an IP packet
- void IpReceived(VH *v, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size, bool mac_broadcast, UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, bool is_local_mac, UINT max_l3_size)
- {
- // Validate arguments
- if (v == NULL || data == NULL)
- {
- return;
- }
- // Deliver the data to the supported high-level protocol
- switch (protocol)
- {
- case IP_PROTO_ICMPV4: // ICMPv4
- if (mac_broadcast == false)
- {
- VirtualIcmpReceived(v, src_ip, dest_ip, data, size, ttl, ip_header, ip_header_size, max_l3_size);
- }
- break;
- case IP_PROTO_TCP: // TCP
- if (mac_broadcast == false)
- {
- VirtualTcpReceived(v, src_ip, dest_ip, data, size, max_l3_size);
- }
- break;
- case IP_PROTO_UDP: // UDP
- VirtualUdpReceived(v, src_ip, dest_ip, data, size, mac_broadcast, is_local_mac, max_l3_size);
- break;
- }
- }
- // Combine the IP packet received to the IP combining object
- void CombineIp(VH *v, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet, UCHAR *head_ip_header_data, UINT head_ip_header_size)
- {
- UINT i;
- IP_PART *p;
- UINT need_size;
- UINT data_size_delta;
- // Validate arguments
- if (c == NULL || data == NULL)
- {
- return;
- }
- // Check the size and offset
- if ((offset + size) > 65535)
- {
- // Do not process packet larger than 64Kbytes
- return;
- }
- if (last_packet == false && c->Size != 0)
- {
- if ((offset + size) > c->Size)
- {
- // Do not process the packet larger than the packet size
- return;
- }
- }
- if (head_ip_header_data != NULL && head_ip_header_size >= sizeof(IPV4_HEADER))
- {
- if (c->HeadIpHeaderData == NULL)
- {
- c->HeadIpHeaderData = Clone(head_ip_header_data, head_ip_header_size);
- c->HeadIpHeaderDataSize = head_ip_header_size;
- }
- }
- need_size = offset + size;
- data_size_delta = c->DataReserved;
- // Ensure sufficient if the buffer is insufficient
- while (c->DataReserved < need_size)
- {
- c->DataReserved = c->DataReserved * 4;
- c->Data = ReAlloc(c->Data, c->DataReserved);
- }
- data_size_delta = c->DataReserved - data_size_delta;
- v->CurrentIpQuota += data_size_delta;
- // Overwrite the data into the buffer
- Copy(((UCHAR *)c->Data) + offset, data, size);
- if (last_packet)
- {
- // If No More Flagment packet arrives, the size of this datagram is finalized
- c->Size = offset + size;
- }
- // Check the overlap between the region which is represented by the offset and size of the
- // existing received list and the region which is represented by the offset and size
- for (i = 0;i < LIST_NUM(c->IpParts);i++)
- {
- UINT moving_size;
- IP_PART *p = LIST_DATA(c->IpParts, i);
- // Check the overlapping between the existing area and head area
- if ((p->Offset <= offset) && ((p->Offset + p->Size) > offset))
- {
- // Compress behind the offset of this packet since a duplication is
- // found in the first part with the existing packet and this packet
- if ((offset + size) <= (p->Offset + p->Size))
- {
- // This packet is buried in the existing packet
- size = 0;
- }
- else
- {
- // Retral region is not overlapped
- moving_size = p->Offset + p->Size - offset;
- offset += moving_size;
- size -= moving_size;
- }
- }
- if ((p->Offset < (offset + size)) && ((p->Offset + p->Size) >= (offset + size)))
- {
- // Compress the size of this packet forward because a duplication is
- // found between the posterior portion the existing packet and this packet
- moving_size = p->Offset + p->Size - offset - size;
- size -= moving_size;
- }
- if ((p->Offset >= offset) && ((p->Offset + p->Size) <= (offset + size)))
- {
- // This packet was overwritten to completely cover an existing packet
- p->Size = 0;
- }
- }
- if (size != 0)
- {
- // Register this packet
- p = ZeroMalloc(sizeof(IP_PART));
- p->Offset = offset;
- p->Size = size;
- Add(c->IpParts, p);
- }
- if (c->Size != 0)
- {
- // Get the total size of the data portion list already received
- UINT total_size = 0;
- UINT i;
- for (i = 0;i < LIST_NUM(c->IpParts);i++)
- {
- IP_PART *p = LIST_DATA(c->IpParts, i);
- total_size += p->Size;
- }
- if (total_size == c->Size)
- {
- // Received all of the IP packet
- IpReceived(v, c->SrcIP, c->DestIP, c->Protocol, c->Data, c->Size, c->MacBroadcast, c->Ttl,
- c->HeadIpHeaderData, c->HeadIpHeaderDataSize, c->SrcIsLocalMacAddr, c->MaxL3Size);
- // Release the combining object
- FreeIpCombine(v, c);
- // Remove from the combining object list
- Delete(v->IpCombine, c);
- }
- }
- }
- // Release the IP combining object
- void FreeIpCombine(VH *v, IP_COMBINE *c)
- {
- UINT i;
- // Validate arguments
- if (c == NULL)
- {
- return;
- }
- // Release the data
- v->CurrentIpQuota -= c->DataReserved;
- Free(c->Data);
- // Release the partial list
- for (i = 0;i < LIST_NUM(c->IpParts);i++)
- {
- IP_PART *p = LIST_DATA(c->IpParts, i);
- Free(p);
- }
- Free(c->HeadIpHeaderData);
- ReleaseList(c->IpParts);
- Free(c);
- }
- // Search the IP combining list
- IP_COMBINE *SearchIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol)
- {
- IP_COMBINE *c, t;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- t.DestIP = dest_ip;
- t.SrcIP = src_ip;
- t.Id = id;
- t.Protocol = protocol;
- c = Search(v->IpCombine, &t);
- return c;
- }
- // Insert by creating a new object to the IP combining list
- IP_COMBINE *InsertIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast, UCHAR ttl, bool src_is_localmac)
- {
- IP_COMBINE *c;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- // Examine the quota
- if ((v->CurrentIpQuota + IP_COMBINE_INITIAL_BUF_SIZE) > IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA)
- {
- // IP packet can not be stored any more
- return NULL;
- }
- c = ZeroMalloc(sizeof(IP_COMBINE));
- c->SrcIsLocalMacAddr = src_is_localmac;
- c->DestIP = dest_ip;
- c->SrcIP = src_ip;
- c->Id = id;
- c->Expire = v->Now + (UINT64)IP_COMBINE_TIMEOUT;
- c->Size = 0;
- c->IpParts = NewList(NULL);
- c->Protocol = protocol;
- c->MacBroadcast = mac_broadcast;
- c->Ttl = ttl;
- // Secure the memory
- c->DataReserved = IP_COMBINE_INITIAL_BUF_SIZE;
- c->Data = Malloc(c->DataReserved);
- v->CurrentIpQuota += c->DataReserved;
- Insert(v->IpCombine, c);
- return c;
- }
- // Initialize the IP combining list
- void InitIpCombineList(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- v->IpCombine = NewList(CompareIpCombine);
- }
- // Release the IP combining list
- void FreeIpCombineList(VH *v)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- for (i = 0;i < LIST_NUM(v->IpCombine);i++)
- {
- IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
- FreeIpCombine(v, c);
- }
- ReleaseList(v->IpCombine);
- }
- // Comparison of IP combining list entry
- int CompareIpCombine(void *p1, void *p2)
- {
- IP_COMBINE *c1, *c2;
- if (p1 == NULL || p2 == NULL)
- {
- return 0;
- }
- c1 = *(IP_COMBINE **)p1;
- c2 = *(IP_COMBINE **)p2;
- if (c1 == NULL || c2 == NULL)
- {
- return 0;
- }
- if (c1->Id > c2->Id)
- {
- return 1;
- }
- else if (c1->Id < c2->Id)
- {
- return -1;
- }
- else if (c1->DestIP > c2->DestIP)
- {
- return 1;
- }
- else if (c1->DestIP < c2->DestIP)
- {
- return -1;
- }
- else if (c1->SrcIP > c2->SrcIP)
- {
- return 1;
- }
- else if (c1->SrcIP < c2->SrcIP)
- {
- return -1;
- }
- else if (c1->Protocol > c2->Protocol)
- {
- return 1;
- }
- else if (c1->Protocol < c2->Protocol)
- {
- return -1;
- }
- return 0;
- }
- // Received an IP packet
- void VirtualIpReceived(VH *v, PKT *packet)
- {
- IPV4_HEADER *ip;
- void *data;
- UINT data_size_recved;
- UINT size;
- UINT ipv4_header_size;
- bool last_packet;
- UCHAR *head_ip_header_data = NULL;
- UINT head_ip_header_size = 0;
- bool is_local_mac = false;
- UINT ip_l3_size;
- // Validate arguments
- if (v == NULL || packet == NULL)
- {
- return;
- }
- ip = packet->L3.IPv4Header;
- if (packet->BroadcastPacket)
- {
- is_local_mac = IsMacAddressLocalFast(packet->MacAddressSrc);
- }
- // Get the size of the IPv4 header
- ipv4_header_size = IPV4_GET_HEADER_LEN(packet->L3.IPv4Header) * 4;
- head_ip_header_size = ipv4_header_size;
- // Calculate the checksum of the IPv4 header
- if (IpCheckChecksum(ip) == false)
- {
- return;
- }
- // Get a pointer to the data
- data = ((UCHAR *)packet->L3.PointerL3) + ipv4_header_size;
- // Register to the ARP table
- ArpIpWasKnown(v, packet->L3.IPv4Header->SrcIP, packet->MacAddressSrc);
- // Get the data size
- size = ip_l3_size = Endian16(ip->TotalLength);
- if (size <= ipv4_header_size)
- {
- // There is no data
- return;
- }
- size -= ipv4_header_size;
- // Get the size of data actually received
- data_size_recved = packet->PacketSize - (ipv4_header_size + MAC_HEADER_SIZE);
- if (data_size_recved < size)
- {
- // Data insufficient (It may be missing on the way)
- return;
- }
- if (IPV4_GET_OFFSET(ip) == 0 && (IPV4_GET_FLAGS(ip) & 0x01) == 0)
- {
- // Because this packet has not been fragmented, it can be delivered to the upper layer immediately
- head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
- IpReceived(v, ip->SrcIP, ip->DstIP, ip->Protocol, data, size, packet->BroadcastPacket, ip->TimeToLive,
- head_ip_header_data, head_ip_header_size, is_local_mac, ip_l3_size);
- }
- else
- {
- // This packet is necessary to combine because it is fragmented
- UINT offset = IPV4_GET_OFFSET(ip) * 8;
- IP_COMBINE *c = SearchIpCombine(v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol);
- if (offset == 0)
- {
- head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
- }
- last_packet = ((IPV4_GET_FLAGS(ip) & 0x01) == 0 ? true : false);
- if (c != NULL)
- {
- // It is the second or subsequent packet
- c->MaxL3Size = MAX(c->MaxL3Size, ip_l3_size);
- CombineIp(v, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
- }
- else
- {
- // Create a combining object because it is the first packet
- c = InsertIpCombine(
- v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol, packet->BroadcastPacket,
- ip->TimeToLive, is_local_mac);
- if (c != NULL)
- {
- c->MaxL3Size = ip_l3_size;
- CombineIp(v, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
- }
- }
- }
- }
- // Send the waiting IP packets from the specified IP address
- void SendWaitingIp(VH *v, UCHAR *mac, UINT dest_ip)
- {
- UINT i;
- LIST *o = NULL;
- // Validate arguments
- if (v == NULL || mac == NULL)
- {
- return;
- }
- // Get a target list
- for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
- {
- IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
- if (w->DestIP == dest_ip)
- {
- if (o == NULL)
- {
- o = NewListFast(NULL);
- }
- Add(o, w);
- }
- }
- // Send the target packets at once
- if (o != NULL)
- {
- for (i = 0;i < LIST_NUM(o);i++)
- {
- IP_WAIT *w = LIST_DATA(o, i);
- // Transmission processing
- VirtualIpSend(v, mac, w->Data, w->Size);
- // Remove from the list
- Delete(v->IpWaitTable, w);
- // Release the memory
- Free(w->Data);
- Free(w);
- }
- ReleaseList(o);
- }
- }
- // Remove the old IP waiting table entries
- void DeleteOldIpWaitTable(VH *v)
- {
- UINT i;
- LIST *o = NULL;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Get the deleting list
- for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
- {
- IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
- if (w->Expire < v->Now)
- {
- if (o == NULL)
- {
- o = NewListFast(NULL);
- }
- Add(o, w);
- }
- }
- // Delete all at once
- if (o != NULL)
- {
- for (i = 0;i < LIST_NUM(o);i++)
- {
- IP_WAIT *w = LIST_DATA(o, i);
- // Remove from the list
- Delete(v->IpWaitTable, w);
- // Release the memory
- Free(w->Data);
- Free(w);
- }
- ReleaseList(o);
- }
- }
- // Poll the IP waiting table
- void PollingIpWaitTable(VH *v)
- {
- // Delete the old table entries
- DeleteOldIpWaitTable(v);
- }
- // Insert the IP packet to the IP waiting table
- void InsertIpWaitTable(VH *v, UINT dest_ip, UINT src_ip, void *data, UINT size)
- {
- IP_WAIT *w;
- // Validate arguments
- if (v == NULL || data == NULL || size == 0)
- {
- return;
- }
- w = ZeroMalloc(sizeof(IP_WAIT));
- w->Data = data;
- w->Size = size;
- w->SrcIP = src_ip;
- w->DestIP = dest_ip;
- w->Expire = v->Now + (UINT64)IP_WAIT_FOR_ARP_TIMEOUT;
- Add(v->IpWaitTable, w);
- }
- // Initialize the IP waiting table
- void InitIpWaitTable(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- v->IpWaitTable = NewList(NULL);
- }
- // Release the IP waiting table
- void FreeIpWaitTable(VH *v)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
- {
- IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
- Free(w->Data);
- Free(w);
- }
- ReleaseList(v->IpWaitTable);
- }
- // MAC address for the IP address is found because something such as an ARP Response arrives
- void ArpIpWasKnown(VH *v, UINT ip, UCHAR *mac)
- {
- // Validate arguments
- if (v == NULL || mac == NULL)
- {
- return;
- }
- // If there is a query for this IP address in the ARP queue, delete it
- DeleteArpWaitTable(v, ip);
- // Update or register in the ARP table
- InsertArpTable(v, mac, ip);
- // Send the IP packets waiting in the IP waiting list
- SendWaitingIp(v, mac, ip);
- }
- // Re-issue ARPs by checking the ARP waiting list
- void PollingArpWaitTable(VH *v)
- {
- UINT i;
- LIST *o;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Initialize the deletion list
- o = NULL;
- // Scan whole ARP waiting list
- for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
- {
- ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
- if (w->GiveupTime < v->Now || (w->GiveupTime - 100 * 1000) > v->Now)
- {
- // Give up the sending of ARP
- if (o == NULL)
- {
- o = NewListFast(NULL);
- }
- Add(o, w);
- }
- else
- {
- if (w->TimeoutTime < v->Now)
- {
- // Send an ARP again
- VirtualArpSendRequest(v, w->IpAddress);
- // Set the next timeout time
- w->TimeoutTime = v->Now + (UINT64)w->NextTimeoutTimeValue;
- // Increase the ARP transmission interval of the second and subsequent
- w->NextTimeoutTimeValue = w->NextTimeoutTimeValue + ARP_REQUEST_TIMEOUT;
- }
- }
- }
- // Remove if there is a ARP waiting record to be deleted
- if (o != NULL)
- {
- for (i = 0;i < LIST_NUM(o);i++)
- {
- ARP_WAIT *w = LIST_DATA(o, i);
- DeleteArpWaitTable(v, w->IpAddress);
- }
- ReleaseList(o);
- }
- }
- // Issue an ARP
- void SendArp(VH *v, UINT ip)
- {
- ARP_WAIT *w;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Examine whether the destination IP address has been registered in the ARP waiting list first
- w = SearchArpWaitTable(v, ip);
- if (w != NULL)
- {
- // Do not do anything because it is already registered
- return;
- }
- // Send an ARP packet first
- VirtualArpSendRequest(v, ip);
- // Register in the ARP waiting list
- w = ZeroMalloc(sizeof(ARP_WAIT));
- w->GiveupTime = v->Now + (UINT64)ARP_REQUEST_GIVEUP;
- w->TimeoutTime = v->Now + (UINT64)ARP_REQUEST_TIMEOUT;
- w->NextTimeoutTimeValue = ARP_REQUEST_TIMEOUT;
- w->IpAddress = ip;
- InsertArpWaitTable(v, w);
- }
- // Delete the ARP waiting table
- void DeleteArpWaitTable(VH *v, UINT ip)
- {
- ARP_WAIT *w;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- w = SearchArpWaitTable(v, ip);
- if (w == NULL)
- {
- return;
- }
- Delete(v->ArpWaitTable, w);
- Free(w);
- }
- // Search the ARP waiting table
- ARP_WAIT *SearchArpWaitTable(VH *v, UINT ip)
- {
- ARP_WAIT *w, t;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- t.IpAddress = ip;
- w = Search(v->ArpWaitTable, &t);
- return w;
- }
- // Register in the ARP waiting table
- void InsertArpWaitTable(VH *v, ARP_WAIT *w)
- {
- // Validate arguments
- if (v == NULL || w == NULL)
- {
- return;
- }
- Add(v->ArpWaitTable, w);
- }
- // Initialize the ARP waiting table
- void InitArpWaitTable(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- v->ArpWaitTable = NewList(CompareArpWaitTable);
- }
- // Release the ARP waiting table
- void FreeArpWaitTable(VH *v)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
- {
- ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
- Free(w);
- }
- ReleaseList(v->ArpWaitTable);
- }
- // Check whether the MAC address is valid
- bool IsMacInvalid(UCHAR *mac)
- {
- UINT i;
- // Validate arguments
- if (mac == NULL)
- {
- return false;
- }
- for (i = 0;i < 6;i++)
- {
- if (mac[i] != 0x00)
- {
- return false;
- }
- }
- return true;
- }
- // Check whether the MAC address is a broadcast address
- bool IsMacBroadcast(UCHAR *mac)
- {
- UINT i;
- // Validate arguments
- if (mac == NULL)
- {
- return false;
- }
- for (i = 0;i < 6;i++)
- {
- if (mac[i] != 0xff)
- {
- return false;
- }
- }
- return true;
- }
- // Insert an entry in the ARP table
- void InsertArpTable(VH *v, UCHAR *mac, UINT ip)
- {
- ARP_ENTRY *e, t;
- // Validate arguments
- if (v == NULL || mac == NULL || ip == 0 || ip == 0xffffffff || IsMacBroadcast(mac) || IsMacInvalid(mac))
- {
- return;
- }
- // Check whether the same IP address is not already registered
- t.IpAddress = ip;
- e = Search(v->ArpTable, &t);
- if (e != NULL)
- {
- // Override this simply because it was registered
- if (Cmp(e->MacAddress, mac, 6) != 0)
- {
- e->Created = v->Now;
- Copy(e->MacAddress, mac, 6);
- }
- e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
- }
- else
- {
- // Create a new entry
- e = ZeroMalloc(sizeof(ARP_ENTRY));
- e->Created = v->Now;
- e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
- Copy(e->MacAddress, mac, 6);
- e->IpAddress = ip;
- Add(v->ArpTable, e);
- }
- }
- // Poll the ARP table
- void PollingArpTable(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- if (v->Now > v->NextArpTablePolling)
- {
- v->NextArpTablePolling = v->Now + (UINT64)ARP_ENTRY_POLLING_TIME;
- RefreshArpTable(v);
- }
- }
- // Remove the old ARP entries
- void RefreshArpTable(VH *v)
- {
- UINT i;
- LIST *o;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- o = NewListFast(NULL);
- for (i = 0;i < LIST_NUM(v->ArpTable);i++)
- {
- ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
- // Check for expired
- if (e->Expire < v->Now)
- {
- // Expired
- Add(o, e);
- }
- }
- // Remove expired entries at once
- for (i = 0;i < LIST_NUM(o);i++)
- {
- ARP_ENTRY *e = LIST_DATA(o, i);
- Delete(v->ArpTable, e);
- Free(e);
- }
- ReleaseList(o);
- }
- // Search the ARP table
- ARP_ENTRY *SearchArpTable(VH *v, UINT ip)
- {
- ARP_ENTRY *e, t;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- t.IpAddress = ip;
- e = Search(v->ArpTable, &t);
- return e;
- }
- // Initialize the ARP table
- void InitArpTable(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- v->ArpTable = NewList(CompareArpTable);
- }
- // Release the ARP table
- void FreeArpTable(VH *v)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Delete all entries
- for (i = 0;i < LIST_NUM(v->ArpTable);i++)
- {
- ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
- Free(e);
- }
- ReleaseList(v->ArpTable);
- }
- // Comparison of the ARP waiting table entry
- int CompareArpWaitTable(void *p1, void *p2)
- {
- ARP_WAIT *e1, *e2;
- if (p1 == NULL || p2 == NULL)
- {
- return 0;
- }
- e1 = *(ARP_WAIT **)p1;
- e2 = *(ARP_WAIT **)p2;
- if (e1 == NULL || e2 == NULL)
- {
- return 0;
- }
- if (e1->IpAddress > e2->IpAddress)
- {
- return 1;
- }
- else if (e1->IpAddress < e2->IpAddress)
- {
- return -1;
- }
- return 0;
- }
- // Comparison of the ARP table entry
- int CompareArpTable(void *p1, void *p2)
- {
- ARP_ENTRY *e1, *e2;
- if (p1 == NULL || p2 == NULL)
- {
- return 0;
- }
- e1 = *(ARP_ENTRY **)p1;
- e2 = *(ARP_ENTRY **)p2;
- if (e1 == NULL || e2 == NULL)
- {
- return 0;
- }
- if (e1->IpAddress > e2->IpAddress)
- {
- return 1;
- }
- else if (e1->IpAddress < e2->IpAddress)
- {
- return -1;
- }
- return 0;
- }
- // Initialize the virtual host
- bool VirtualInit(VH *v)
- {
- // Initialize the log
- v->Logger = NULL;
- LockVirtual(v);
- {
- // Initialize
- v->Cancel = NewCancel();
- v->SendQueue = NewQueue();
- }
- UnlockVirtual(v);
- // Counter reset
- v->Counter->c = 0;
- v->DhcpId = 0;
- // Initialize the ARP table
- InitArpTable(v);
- // Initialize the ARP waiting table
- InitArpWaitTable(v);
- // Initialize the IP waiting table
- InitIpWaitTable(v);
- // Initialize the IP combining list
- InitIpCombineList(v);
- // Initialize the NAT
- InitNat(v);
- // Initialize the DHCP server
- InitDhcpServer(v);
- // Other initialization
- v->flag1 = false;
- v->NextArpTablePolling = Tick64() + (UINT64)ARP_ENTRY_POLLING_TIME;
- v->CurrentIpQuota = 0;
- v->Active = true;
- return true;
- }
- bool VirtualPaInit(SESSION *s)
- {
- VH *v;
- // Validate arguments
- if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
- {
- return false;
- }
- return VirtualInit(v);
- }
- // Get the cancel object of the virtual host
- CANCEL *VirtualPaGetCancel(SESSION *s)
- {
- VH *v;
- // Validate arguments
- if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
- {
- return NULL;
- }
- AddRef(v->Cancel->ref);
- return v->Cancel;
- }
- // Get the next packet from the virtual host
- UINT VirtualGetNextPacket(VH *v, void **data)
- {
- UINT ret = 0;
- START:
- // Examine the transmission queue
- LockQueue(v->SendQueue);
- {
- BLOCK *block = GetNext(v->SendQueue);
- if (block != NULL)
- {
- // There is a packet
- ret = block->Size;
- *data = block->Buf;
- // Discard the structure
- Free(block);
- }
- }
- UnlockQueue(v->SendQueue);
- if (ret == 0)
- {
- LockVirtual(v);
- {
- v->Now = Tick64();
- // Polling process
- VirtualPolling(v);
- }
- UnlockVirtual(v);
- if (v->SendQueue->num_item != 0)
- {
- goto START;
- }
- }
- return ret;
- }
- UINT VirtualPaGetNextPacket(SESSION *s, void **data)
- {
- VH *v;
- // Validate arguments
- if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
- {
- return INFINITE;
- }
- return VirtualGetNextPacket(v, data);
- }
- // Polling process (Always called once in a SessionMain loop)
- void VirtualPolling(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // DHCP polling
- PollingDhcpServer(v);
- // NAT polling
- PoolingNat(v);
- // Clear the old ARP table entries
- PollingArpTable(v);
- // Poll the ARP waiting list
- PollingArpWaitTable(v);
- // Poll the IP waiting list
- PollingIpWaitTable(v);
- // Poll the IP combining list
- PollingIpCombine(v);
- // Beacon transmission procedure
- PollingBeacon(v);
- }
- // Beacon transmission procedure
- void PollingBeacon(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- if (v->LastSendBeacon == 0 ||
- ((v->LastSendBeacon + BEACON_SEND_INTERVAL) <= Tick64()))
- {
- v->LastSendBeacon = Tick64();
- SendBeacon(v);
- }
- }
- // Send a Layer-2 packet
- void VirtualLayer2Send(VH *v, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
- {
- MAC_HEADER *mac_header;
- UCHAR *buf;
- BLOCK *block;
- // Validate arguments
- if (v == NULL || dest_mac == NULL || src_mac == NULL || data == NULL || size > (MAX_PACKET_SIZE - sizeof(MAC_HEADER)))
- {
- return;
- }
- // Create buffer
- buf = Malloc(MAC_HEADER_SIZE + size);
- // MAC header
- mac_header = (MAC_HEADER *)&buf[0];
- Copy(mac_header->DestAddress, dest_mac, 6);
- Copy(mac_header->SrcAddress, src_mac, 6);
- mac_header->Protocol = Endian16(protocol);
- // Copy data
- Copy(&buf[sizeof(MAC_HEADER)], data, size);
- // Size
- size += sizeof(MAC_HEADER);
- // Generate the packet
- block = NewBlock(buf, size, 0);
- // Insert into the queue
- LockQueue(v->SendQueue);
- {
- InsertQueue(v->SendQueue, block);
- }
- UnlockQueue(v->SendQueue);
- // Cancel
- Cancel(v->Cancel);
- }
- // Send an IP packet (with automatic fragmentation)
- void SendIp(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size)
- {
- SendIpEx(v, dest_ip, src_ip, protocol, data, size, 0);
- }
- void SendIpEx(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size, UCHAR ttl)
- {
- UINT mss;
- UCHAR *buf;
- USHORT offset;
- USHORT id;
- USHORT total_size;
- UINT size_of_this_packet;
- // Validate arguments
- if (v == NULL || data == NULL || size == 0 || size > MAX_IP_DATA_SIZE_TOTAL)
- {
- return;
- }
- // Maximum segment size
- mss = v->IpMss;
- // Buffer
- buf = (UCHAR *)data;
- // ID
- id = (v->NextId++);
- // Total size
- total_size = (USHORT)size;
- // Start to split
- offset = 0;
- while (true)
- {
- bool last_packet = false;
- // Gets the size of this packet
- size_of_this_packet = MIN((USHORT)mss, (total_size - offset));
- if ((offset + (USHORT)size_of_this_packet) == total_size)
- {
- last_packet = true;
- }
- // Transmit the fragmented packet
- SendFragmentedIp(v, dest_ip, src_ip, id,
- total_size, offset, protocol, buf + offset, size_of_this_packet, NULL, ttl);
- if (last_packet)
- {
- break;
- }
- offset += (USHORT)size_of_this_packet;
- }
- }
- // Reserve to send the fragmented IP packet
- void SendFragmentedIp(VH *v, UINT dest_ip, UINT src_ip, USHORT id, USHORT total_size, USHORT offset, UCHAR protocol, void *data, UINT size, UCHAR *dest_mac, UCHAR ttl)
- {
- UCHAR *buf;
- IPV4_HEADER *ip;
- ARP_ENTRY *arp;
- // Validate arguments
- if (v == NULL || data == NULL || size == 0)
- {
- return;
- }
- // Memory allocation
- buf = Malloc(size + IP_HEADER_SIZE);
- ip = (IPV4_HEADER *)&buf[0];
- // IP header construction
- ip->VersionAndHeaderLength = 0;
- IPV4_SET_VERSION(ip, 4);
- IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
- ip->TypeOfService = DEFAULT_IP_TOS;
- ip->TotalLength = Endian16((USHORT)(size + IP_HEADER_SIZE));
- ip->Identification = Endian16(id);
- ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
- IPV4_SET_OFFSET(ip, (offset / 8));
- if ((offset + size) >= total_size)
- {
- IPV4_SET_FLAGS(ip, 0x00);
- }
- else
- {
- IPV4_SET_FLAGS(ip, 0x01);
- }
- ip->TimeToLive = (ttl == 0 ? DEFAULT_IP_TTL : ttl);
- ip->Protocol = protocol;
- ip->Checksum = 0;
- ip->SrcIP = src_ip;
- ip->DstIP = dest_ip;
- // Checksum calculation
- ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
- // Data copy
- Copy(buf + IP_HEADER_SIZE, data, size);
- if (dest_mac == NULL)
- {
- if (ip->DstIP == 0xffffffff ||
- (IsInNetwork(ip->DstIP, v->HostIP, v->HostMask) && (ip->DstIP & (~v->HostMask)) == (~v->HostMask)))
- {
- // Broadcast address
- dest_mac = broadcast;
- }
- else
- {
- // Send an ARP query if the destination MAC address is unknown
- arp = SearchArpTable(v, dest_ip);
- if (arp != NULL)
- {
- dest_mac = arp->MacAddress;
- }
- }
- }
- if (dest_mac != NULL)
- {
- // Send the packet immediately
- VirtualIpSend(v, dest_mac, buf, size + IP_HEADER_SIZE);
- // Packet data may be released
- Free(buf);
- }
- else
- {
- // Because this packet still can not be transferred, add it to the IP waiting table
- InsertIpWaitTable(v, dest_ip, src_ip, buf, size + IP_HEADER_SIZE);
- // Issue an ARP
- SendArp(v, dest_ip);
- }
- }
- // Send an IP packet (fragmented)
- void VirtualIpSend(VH *v, UCHAR *dest_mac, void *data, UINT size)
- {
- // Validate arguments
- if (v == NULL || dest_mac == NULL || data == NULL || size == 0)
- {
- return;
- }
- // Transmission
- VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_IPV4, data, size);
- }
- // Send an ARP request packet
- void VirtualArpSendRequest(VH *v, UINT dest_ip)
- {
- ARPV4_HEADER arp;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Build the ARP header
- arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
- arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
- arp.HardwareSize = 6;
- arp.ProtocolSize = 4;
- arp.Operation = Endian16(ARP_OPERATION_REQUEST);
- Copy(arp.SrcAddress, v->MacAddress, 6);
- arp.SrcIP = v->HostIP;
- Zero(&arp.TargetAddress, 6);
- arp.TargetIP = dest_ip;
- // Transmission
- VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
- }
- // Send an ARP response packet
- void VirtualArpSendResponse(VH *v, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
- {
- ARPV4_HEADER arp;
- // Validate arguments
- if (v == NULL || dest_mac == NULL)
- {
- return;
- }
- // Build the ARP header
- arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
- arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
- arp.HardwareSize = 6;
- arp.ProtocolSize = 4;
- arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
- Copy(arp.SrcAddress, v->MacAddress, 6);
- Copy(arp.TargetAddress, dest_mac, 6);
- arp.SrcIP = src_ip;
- arp.TargetIP = dest_ip;
- // Transmission
- VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(ARPV4_HEADER));
- }
- // An ARP request packet was received
- void VirtualArpResponseRequest(VH *v, PKT *packet)
- {
- ARPV4_HEADER *arp;
- // Validate arguments
- if (v == NULL || packet == NULL)
- {
- return;
- }
- arp = packet->L3.ARPv4Header;
- // Memory the information of the host IP address and the MAC address of the other party
- ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
- // Search whether it matches with the IP address of this host
- if (v->HostIP == arp->TargetIP)
- {
- // Respond since the match
- VirtualArpSendResponse(v, arp->SrcAddress, arp->SrcIP, v->HostIP);
- return;
- }
- // Do nothing if it doesn't match
- }
- // An ARP response packet is received
- void VirtualArpResponseReceived(VH *v, PKT *packet)
- {
- ARPV4_HEADER *arp;
- // Validate arguments
- if (v == NULL || packet == NULL)
- {
- return;
- }
- arp = packet->L3.ARPv4Header;
- // Regard this information as known information
- ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
- }
- // Received an ARP packet
- void VirtualArpReceived(VH *v, PKT *packet)
- {
- ARPV4_HEADER *arp;
- // Validate arguments
- if (v == NULL || packet == NULL)
- {
- return;
- }
- arp = packet->L3.ARPv4Header;
- if (Endian16(arp->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET)
- {
- // Ignore if hardware type is other than Ethernet
- return;
- }
- if (Endian16(arp->ProtocolType) != MAC_PROTO_IPV4)
- {
- // Ignore if the protocol type is a non-IPv4
- return;
- }
- if (arp->HardwareSize != 6 || arp->ProtocolSize != 4)
- {
- // Ignore because the size of protocol address or hardware address is invalid
- return;
- }
- // Check the source MAC address
- if (Cmp(arp->SrcAddress, packet->MacAddressSrc, 6) != 0)
- {
- // MAC address in the MAC header and the MAC address of the ARP packet are different
- return;
- }
- switch (Endian16(arp->Operation))
- {
- case ARP_OPERATION_REQUEST: // ARP request
- VirtualArpResponseRequest(v, packet);
- break;
- case ARP_OPERATION_RESPONSE: // ARP response
- VirtualArpResponseReceived(v, packet);
- break;
- }
- }
- // Release the DHCP server
- void FreeDhcpServer(VH *v)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Remove the all lease entries
- for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
- {
- DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
- FreeDhcpLease(d);
- }
- ReleaseList(v->DhcpLeaseList);
- v->DhcpLeaseList = NULL;
- }
- // Initialize the DHCP server
- void InitDhcpServer(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Create a list
- v->DhcpLeaseList = NewList(CompareDhcpLeaseList);
- }
- // Search for a DHCP lease item by the IP address
- DHCP_LEASE *SearchDhcpLeaseByIp(VH *v, UINT ip)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return NULL;
- }
- for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
- {
- DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
- if (d->IpAddress == ip)
- {
- return d;
- }
- }
- return NULL;
- }
- // Search for a DHCP lease item by the MAC address
- DHCP_LEASE *SearchDhcpLeaseByMac(VH *v, UCHAR *mac)
- {
- DHCP_LEASE *d, t;
- // Validate arguments
- if (v == NULL || mac == NULL)
- {
- return NULL;
- }
- Copy(&t.MacAddress, mac, 6);
- d = Search(v->DhcpLeaseList, &t);
- return d;
- }
- // Release the DHCP lease item
- void FreeDhcpLease(DHCP_LEASE *d)
- {
- // Validate arguments
- if (d == NULL)
- {
- return;
- }
- Free(d->Hostname);
- Free(d);
- }
- // Create a DHCP lease item
- DHCP_LEASE *NewDhcpLease(UINT expire, UCHAR *mac_address, UINT ip, UINT mask, char *hostname)
- {
- DHCP_LEASE *d;
- // Validate arguments
- if (mac_address == NULL || hostname == NULL)
- {
- return NULL;
- }
- d = ZeroMalloc(sizeof(DHCP_LEASE));
- d->LeasedTime = (UINT64)Tick64();
- if (expire == INFINITE)
- {
- d->ExpireTime = INFINITE;
- }
- else
- {
- d->ExpireTime = d->LeasedTime + (UINT64)expire;
- }
- d->IpAddress = ip;
- d->Mask = mask;
- d->Hostname = CopyStr(hostname);
- Copy(d->MacAddress, mac_address, 6);
- return d;
- }
- // Comparison of the items in the DHCP list
- int CompareDhcpLeaseList(void *p1, void *p2)
- {
- DHCP_LEASE *d1, *d2;
- // Validate arguments
- if (p1 == NULL || p2 == NULL)
- {
- return 0;
- }
- d1 = *(DHCP_LEASE **)p1;
- d2 = *(DHCP_LEASE **)p2;
- if (d1 == NULL || d2 == NULL)
- {
- return 0;
- }
- return Cmp(d1->MacAddress, d2->MacAddress, 6);
- }
- // Poll the DHCP server
- void PollingDhcpServer(VH *v)
- {
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- if (v->LastDhcpPolling != 0)
- {
- if ((v->LastDhcpPolling + (UINT64)DHCP_POLLING_INTERVAL) > v->Now &&
- v->LastDhcpPolling < v->Now)
- {
- return;
- }
- }
- v->LastDhcpPolling = v->Now;
- // Remove expired entries
- FIRST_LIST:
- for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
- {
- DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
- if (d->ExpireTime < v->Now)
- {
- FreeDhcpLease(d);
- Delete(v->DhcpLeaseList, d);
- goto FIRST_LIST;
- }
- }
- }
- // Correspond to the DHCP REQUEST
- UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip)
- {
- UINT ret;
- // Validate arguments
- if (v == NULL || mac == NULL)
- {
- return 0;
- }
- ret = ServeDhcpDiscover(v, mac, request_ip);
- if (ret != request_ip)
- {
- if (request_ip != 0)
- {
- // Raise an error if the requested IP address cannot to be assigned
- return 0;
- }
- }
- return ret;
- }
- // Correspond to the DHCP DISCOVER
- UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip)
- {
- UINT ret = 0;
- // Validate arguments
- if (v == NULL || mac == NULL)
- {
- return 0;
- }
- if (request_ip != 0)
- {
- // IP address is specified
- DHCP_LEASE *d = SearchDhcpLeaseByIp(v, request_ip);
- if (d != NULL)
- {
- // If an entry for the same IP address already exists,
- // check whether it is a request from the same MAC address
- if (Cmp(mac, d->MacAddress, 6) == 0)
- {
- // Examine whether the specified IP address is within the range of assignment
- if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
- Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
- {
- // Accept if within the range
- ret = request_ip;
- }
- }
- }
- else
- {
- // Examine whether the specified IP address is within the range of assignment
- if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
- Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
- {
- // Accept if within the range
- ret = request_ip;
- }
- else
- {
- // Propose an IP in the range since it's a Discover although It is out of range
- }
- }
- }
- if (ret == 0)
- {
- // If there is any entry with the same MAC address
- // that are already registered, use it with priority
- DHCP_LEASE *d = SearchDhcpLeaseByMac(v, mac);
- if (d != NULL)
- {
- // Examine whether the found IP address is in the allocation region
- if (Endian32(v->DhcpIpStart) <= Endian32(d->IpAddress) &&
- Endian32(d->IpAddress) <= Endian32(v->DhcpIpEnd))
- {
- // Use the IP address if it's found within the range
- ret = d->IpAddress;
- }
- }
- }
- if (ret == 0)
- {
- // Take an appropriate IP addresses that can be assigned newly
- ret = GetFreeDhcpIpAddress(v);
- }
- return ret;
- }
- // Take an appropriate IP addresses that can be assigned newly
- UINT GetFreeDhcpIpAddress(VH *v)
- {
- UINT ip_start, ip_end;
- UINT i;
- // Validate arguments
- if (v == NULL)
- {
- return 0;
- }
- ip_start = Endian32(v->DhcpIpStart);
- ip_end = Endian32(v->DhcpIpEnd);
- for (i = ip_start; i <= ip_end;i++)
- {
- UINT ip = Endian32(i);
- if (SearchDhcpLeaseByIp(v, ip) == NULL)
- {
- // A free IP address is found
- return ip;
- }
- }
- // There is no free address
- return 0;
- }
- // Virtual DHCP Server
- void VirtualDhcpServer(VH *v, PKT *p)
- {
- DHCPV4_HEADER *dhcp;
- UCHAR *data;
- UINT size;
- UINT dhcp_header_size;
- UINT dhcp_data_offset;
- UINT tran_id;
- UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
- bool ok;
- DHCP_OPTION_LIST *opt;
- // Validate arguments
- if (v == NULL || p == NULL)
- {
- return;
- }
- if (v->NativeNat != NULL)
- {
- if (Cmp(p->MacAddressSrc, v->NativeNat->CurrentMacAddress, 6) == 0)
- {
- // DHCP server is kept from responding for the native NAT interface
- // ** Not be needed to return yet **
- //return;
- }
- }
- dhcp = p->L7.DHCPv4Header;
- tran_id = Endian32(dhcp->TransactionId);
- // Get the DHCP data and size
- dhcp_header_size = sizeof(DHCPV4_HEADER);
- dhcp_data_offset = (UINT)(((UCHAR *)p->L7.DHCPv4Header) - ((UCHAR *)p->MacHeader) + dhcp_header_size);
- data = ((UCHAR *)dhcp) + dhcp_header_size;
- size = p->PacketSize - dhcp_data_offset;
- if (dhcp_header_size < 5)
- {
- // Data size is invalid
- return;
- }
- // Search for Magic Cookie
- ok = false;
- while (size >= 5)
- {
- if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
- {
- // Found
- data += 4;
- size -= 4;
- ok = true;
- break;
- }
- data++;
- size--;
- }
- if (ok == false)
- {
- // The packet is invalid
- return;
- }
- // Parse DHCP options list
- opt = ParseDhcpOptionList(data, size);
- if (opt == NULL)
- {
- // The packet is invalid
- return;
- }
- if (StartWith(opt->Hostname, NN_HOSTNAME_STARTWITH) || StartWith(opt->Hostname, NN_HOSTNAME_STARTWITH2))
- {
- Free(opt);
- return;
- }
- if (dhcp->OpCode == 1 && (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST || opt->Opcode == DHCP_INFORM))
- {
- // Operate as the server
- UINT ip = 0;
- if (opt->RequestedIp == 0)
- {
- opt->RequestedIp = p->L3.IPv4Header->SrcIP;
- }
- if (opt->Opcode == DHCP_DISCOVER)
- {
- // Return an IP address that can be used
- ip = ServeDhcpDiscover(v, p->MacAddressSrc, opt->RequestedIp);
- }
- else if (opt->Opcode == DHCP_REQUEST)
- {
- // Determine the IP address
- ip = ServeDhcpRequest(v, p->MacAddressSrc, opt->RequestedIp);
- }
- if (ip != 0 || opt->Opcode == DHCP_INFORM)
- {
- // Respond if there is providable IP address
- if (opt->Opcode == DHCP_REQUEST)
- {
- DHCP_LEASE *d;
- char mac[MAX_SIZE];
- char str[MAX_SIZE];
- // Remove old records with the same IP address
- d = SearchDhcpLeaseByIp(v, ip);
- if (d != NULL)
- {
- FreeDhcpLease(d);
- Delete(v->DhcpLeaseList, d);
- }
- // Create a new entry
- d = NewDhcpLease(v->DhcpExpire, p->MacAddressSrc,
- ip, v->DhcpMask,
- opt->Hostname);
- d->Id = ++v->DhcpId;
- Add(v->DhcpLeaseList, d);
- MacToStr(mac, sizeof(mac), d->MacAddress);
- IPToStr32(str, sizeof(str), d->IpAddress);
- NLog(v, "LH_NAT_DHCP_CREATED", d->Id, mac, str, d->Hostname, v->DhcpExpire / 1000);
- }
- // Respond
- if (true)
- {
- DHCP_OPTION_LIST ret;
- LIST *o;
- Zero(&ret, sizeof(ret));
- ret.Opcode = (opt->Opcode == DHCP_DISCOVER ? DHCP_OFFER : DHCP_ACK);
- ret.ServerAddress = v->HostIP;
- if (v->DhcpExpire == INFINITE)
- {
- ret.LeaseTime = INFINITE;
- }
- else
- {
- ret.LeaseTime = Endian32(v->DhcpExpire / 1000);
- }
- if (opt->Opcode == DHCP_INFORM)
- {
- ret.LeaseTime = 0;
- }
- StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
- ret.SubnetMask = v->DhcpMask;
- ret.DnsServer = v->DhcpDns;
- ret.DnsServer2 = v->DhcpDns2;
- ret.Gateway = v->DhcpGateway;
- if (GetGlobalServerFlag(GSF_DISABLE_PUSH_ROUTE) == 0)
- {
- Copy(&ret.ClasslessRoute, &v->PushRoute, sizeof(DHCP_CLASSLESS_ROUTE_TABLE));
- if (IsIpcMacAddress(p->MacAddressSrc))
- {
- if (ret.Gateway == 0)
- {
- // If the default gateway is not specified, add the static routing table
- // entry for the local IP subnet
- // (for PPP clients)
- IP dhcp_ip;
- IP dhcp_mask;
- IP dhcp_network;
- UINTToIP(&dhcp_ip, ip);
- if (ip == 0)
- {
- UINTToIP(&dhcp_ip, p->L3.IPv4Header->SrcIP);
- }
- UINTToIP(&dhcp_mask, v->DhcpMask);
- IPAnd4(&dhcp_network, &dhcp_ip, &dhcp_mask);
- if (GetBestClasslessRoute(&ret.ClasslessRoute, &dhcp_ip) == NULL)
- {
- if (ret.ClasslessRoute.NumExistingRoutes < MAX_DHCP_CLASSLESS_ROUTE_ENTRIES)
- {
- DHCP_CLASSLESS_ROUTE *cr = &ret.ClasslessRoute.Entries[ret.ClasslessRoute.NumExistingRoutes];
- cr->Exists = true;
- UINTToIP(&cr->Gateway, v->HostIP);
- if (v->UseNat == false && ret.ClasslessRoute.NumExistingRoutes >= 1)
- {
- Copy(&cr->Gateway, &ret.ClasslessRoute.Entries[0].Gateway, sizeof(IP));
- }
- Copy(&cr->Network, &dhcp_network, sizeof(IP));
- Copy(&cr->SubnetMask, &dhcp_mask, sizeof(IP));
- cr->SubnetMaskLen = SubnetMaskToInt(&dhcp_mask);
- ret.ClasslessRoute.NumExistingRoutes++;
- }
- }
- }
- }
- }
- if (opt->Opcode != DHCP_INFORM)
- {
- char client_mac[MAX_SIZE];
- char client_ip[64];
- IP ips;
- BinToStr(client_mac, sizeof(client_mac), p->MacAddressSrc, 6);
- UINTToIP(&ips, ip);
- IPToStr(client_ip, sizeof(client_ip), &ips);
- Debug("DHCP %s : %s given %s\n",
- ret.Opcode == DHCP_OFFER ? "DHCP_OFFER" : "DHCP_ACK",
- client_mac, client_ip);
- }
- // Build a DHCP option
- o = BuildDhcpOption(&ret);
- if (o != NULL)
- {
- BUF *b = BuildDhcpOptionsBuf(o);
- if (b != NULL)
- {
- UINT dest_ip = p->L3.IPv4Header->SrcIP;
- if (dest_ip == 0)
- {
- dest_ip = 0xffffffff;
- }
- // Transmission
- VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
- ip, dhcp->ClientMacAddress, b, dhcp->HardwareType, dhcp->HardwareAddressSize);
- // Release the memory
- FreeBuf(b);
- }
- FreeDhcpOptions(o);
- }
- }
- }
- else
- {
- // There is no IP address that can be provided
- DHCP_OPTION_LIST ret;
- LIST *o;
- Zero(&ret, sizeof(ret));
- ret.Opcode = DHCP_NACK;
- ret.ServerAddress = v->HostIP;
- StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
- ret.SubnetMask = v->DhcpMask;
- // Build the DHCP option
- o = BuildDhcpOption(&ret);
- if (o != NULL)
- {
- BUF *b = BuildDhcpOptionsBuf(o);
- if (b != NULL)
- {
- UINT dest_ip = p->L3.IPv4Header->SrcIP;
- if (dest_ip == 0)
- {
- dest_ip = 0xffffffff;
- }
- // Transmission
- VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
- ip, dhcp->ClientMacAddress, b, dhcp->HardwareType, dhcp->HardwareAddressSize);
- // Release the memory
- FreeBuf(b);
- }
- FreeDhcpOptions(o);
- }
- }
- }
- // Release the memory
- Free(opt);
- }
- // Submit the DHCP response packet
- void VirtualDhcpSend(VH *v, UINT tran_id, UINT dest_ip, UINT dest_port,
- UINT new_ip, UCHAR *client_mac, BUF *b, UINT hw_type, UINT hw_addr_size)
- {
- UINT blank_size = 128 + 64;
- UINT dhcp_packet_size;
- UINT magic = Endian32(DHCP_MAGIC_COOKIE);
- DHCPV4_HEADER *dhcp;
- void *magic_cookie_addr;
- void *buffer_addr;
- // Validate arguments
- if (v == NULL || b == NULL)
- {
- return;
- }
- // Calculate the DHCP packet size
- dhcp_packet_size = blank_size + sizeof(DHCPV4_HEADER) + sizeof(magic) + b->Size;
- if (dhcp_packet_size < DHCP_MIN_SIZE)
- {
- // Padding
- dhcp_packet_size = DHCP_MIN_SIZE;
- }
- // Create a header
- dhcp = ZeroMalloc(dhcp_packet_size);
- dhcp->OpCode = 2;
- dhcp->HardwareType = hw_type;
- dhcp->HardwareAddressSize = hw_addr_size;
- dhcp->Hops = 0;
- dhcp->TransactionId = Endian32(tran_id);
- dhcp->Seconds = 0;
- dhcp->Flags = 0;
- dhcp->YourIP = new_ip;
- dhcp->ServerIP = v->HostIP;
- Copy(dhcp->ClientMacAddress, client_mac, 6);
- // Calculate the address
- magic_cookie_addr = (((UCHAR *)dhcp) + sizeof(DHCPV4_HEADER) + blank_size);
- buffer_addr = ((UCHAR *)magic_cookie_addr) + sizeof(magic);
- // Magic Cookie
- Copy(magic_cookie_addr, &magic, sizeof(magic));
- // Buffer
- Copy(buffer_addr, b->Buf, b->Size);
- // Transmission
- SendUdp(v, dest_ip, dest_port, v->HostIP, NAT_DHCP_SERVER_PORT, dhcp, dhcp_packet_size);
- Free(dhcp);
- }
- // Virtual host: Process the Layer2
- void VirtualLayer2(VH *v, PKT *packet)
- {
- bool ok;
- // Validate arguments
- if (packet == NULL || v == NULL)
- {
- return;
- }
- // Packet filter
- if (VirtualLayer2Filter(v, packet) == false)
- {
- // Packet was ignored
- return;
- }
- ok = false;
- if (packet->TypeL3 == L3_IPV4 && packet->TypeL4 == L4_UDP && packet->TypeL7 == L7_DHCPV4)
- {
- if (v->UseDhcp)
- {
- // A special treatment on the DHCP packet
- if (packet->BroadcastPacket || Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
- {
- // Virtual DHCP server processing
- VirtualDhcpServer(v, packet);
- ok = true;
- }
- }
- }
- if (ok == false)
- {
- // The process for each supported protocol
- switch (packet->TypeL3)
- {
- case L3_ARPV4: // ARPv4
- VirtualArpReceived(v, packet);
- break;
- case L3_IPV4: // IPv4
- VirtualIpReceived(v, packet);
- break;
- }
- }
- }
- // Packet filter (Blocking packets to other than me)
- bool VirtualLayer2Filter(VH *v, PKT *packet)
- {
- // Validate arguments
- if (v == NULL || packet == NULL)
- {
- return false;
- }
- // Pass through if broadcast packet
- if (packet->BroadcastPacket)
- {
- return true;
- }
- // Ignore if the sender of the packet is myself
- if (Cmp(packet->MacAddressSrc, v->MacAddress, 6) == 0)
- {
- return false;
- }
- // Pass through in the case of a packet addressed to me
- if (Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
- {
- return true;
- }
- // Discard if the other packets
- return false;
- }
- // The virtual host is made to receive a packet
- bool VirtualPutPacket(VH *v, void *data, UINT size)
- {
- if (data == NULL)
- {
- // Flush
- v->flag1 = false;
- if (v->NativeNat != NULL)
- {
- if (v->NativeNat->SendStateChanged)
- {
- TUBE *halt_tube = NULL;
- Lock(v->NativeNat->Lock);
- {
- if (v->NativeNat->HaltTube != NULL)
- {
- halt_tube = v->NativeNat->HaltTube;
- AddRef(halt_tube->Ref);
- }
- }
- Unlock(v->NativeNat->Lock);
- if (halt_tube != NULL)
- {
- TubeFlushEx(halt_tube, true);
- v->NativeNat->SendStateChanged = false;
- ReleaseTube(halt_tube);
- }
- }
- }
- }
- else
- {
- // Interpret the received packet
- PKT *packet = ParsePacket(data, size);
- if (v->flag1 == false)
- {
- v->flag1 = true;
- v->Now = Tick64();
- }
- // Lock the entire virtual machine in here
- LockVirtual(v);
- {
- if (packet != NULL)
- {
- // Process the Layer-2
- VirtualLayer2(v, packet);
- // Release the packet structure
- FreePacket(packet);
- }
- }
- UnlockVirtual(v);
- Free(data);
- }
- return true;
- }
- bool VirtualPaPutPacket(SESSION *s, void *data, UINT size)
- {
- VH *v;
- // Validate arguments
- if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
- {
- return false;
- }
- return VirtualPutPacket(v, data, size);
- }
- // Get the options for the virtual host
- void GetVirtualHostOption(VH *v, VH_OPTION *o)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- LockVirtual(v);
- {
- Zero(o, sizeof(VH_OPTION));
- // MAC address
- Copy(o->MacAddress, v->MacAddress, 6);
- // Host information
- UINTToIP(&o->Ip, v->HostIP);
- UINTToIP(&o->Mask, v->HostMask);
- o->Mtu = v->Mtu;
- // NAT timeout information
- o->NatTcpTimeout = v->NatTcpTimeout / 1000;
- o->NatUdpTimeout = v->NatUdpTimeout / 1000;
- // NAT using flag
- o->UseNat = v->UseNat;
- // DHCP using flag
- o->UseDhcp = v->UseDhcp;
- // IP address range for DHCP distribution
- UINTToIP(&o->DhcpLeaseIPStart, v->DhcpIpStart);
- UINTToIP(&o->DhcpLeaseIPEnd, v->DhcpIpEnd);
- // Subnet mask
- UINTToIP(&o->DhcpSubnetMask, v->DhcpMask);
- // Expiration date
- if (v->DhcpExpire != INFINITE)
- {
- o->DhcpExpireTimeSpan = v->DhcpExpire / 1000;
- }
- else
- {
- o->DhcpExpireTimeSpan = INFINITE;
- }
- // Gateway address
- UINTToIP(&o->DhcpGatewayAddress, v->DhcpGateway);
- // DNS server address
- UINTToIP(&o->DhcpDnsServerAddress, v->DhcpDns);
- UINTToIP(&o->DhcpDnsServerAddress2, v->DhcpDns2);
- // Domain name
- StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), v->DhcpDomain);
- // Save a log
- o->SaveLog = v->SaveLog;
- // Pushing route option
- BuildClasslessRouteTableStr(o->DhcpPushRoutes, sizeof(o->DhcpPushRoutes), &v->PushRoute);
- o->ApplyDhcpPushRoutes = true;
- }
- UnlockVirtual(v);
- }
- // Set the option to the virtual host
- void SetVirtualHostOption(VH *v, VH_OPTION *vo)
- {
- UINT i;
- // Validate arguments
- if (v == NULL || vo == NULL)
- {
- return;
- }
- LockVirtual(v);
- {
- // Set the MAC address
- for (i = 0;i < 6;i++)
- {
- if (vo->MacAddress[i] != 0)
- {
- Copy(v->MacAddress, vo->MacAddress, 6);
- break;
- }
- }
- // Set the host information list
- v->HostIP = IPToUINT(&vo->Ip);
- v->HostMask = IPToUINT(&vo->Mask);
- // Set the MTU, MMS
- v->Mtu = MIN(vo->Mtu, MAX_L3_DATA_SIZE);
- if (v->Mtu == 0)
- {
- v->Mtu = MAX_L3_DATA_SIZE;
- }
- v->Mtu = MAX(v->Mtu, TCP_HEADER_SIZE + IP_HEADER_SIZE + MAC_HEADER_SIZE + 8);
- v->IpMss = ((v->Mtu - IP_HEADER_SIZE) / 8) * 8;
- v->TcpMss = ((v->IpMss - TCP_HEADER_SIZE) / 8) * 8;
- v->UdpMss = ((v->IpMss - UDP_HEADER_SIZE) / 8) * 8;
- if (vo->NatTcpTimeout != 0)
- {
- v->NatTcpTimeout = MIN(vo->NatTcpTimeout, 4000000) * 1000;
- }
- if (vo->NatUdpTimeout != 0)
- {
- v->NatUdpTimeout = MIN(vo->NatUdpTimeout, 4000000) * 1000;
- }
- v->NatTcpTimeout = MAKESURE(v->NatTcpTimeout, NAT_TCP_MIN_TIMEOUT, NAT_TCP_MAX_TIMEOUT);
- v->NatUdpTimeout = MAKESURE(v->NatUdpTimeout, NAT_UDP_MIN_TIMEOUT, NAT_UDP_MAX_TIMEOUT);
- Debug("Timeout: %d , %d\n", v->NatTcpTimeout, v->NatUdpTimeout);
- // NAT using flag
- v->UseNat = vo->UseNat;
- // DHCP using flag
- v->UseDhcp = vo->UseDhcp;
- // Expiration date
- if (vo->DhcpExpireTimeSpan == 0 || vo->DhcpExpireTimeSpan == INFINITE)
- {
- v->DhcpExpire = INFINITE;
- }
- else
- {
- v->DhcpExpire = MAKESURE(DHCP_MIN_EXPIRE_TIMESPAN,
- MIN(vo->DhcpExpireTimeSpan * 1000, 2000000000),
- INFINITE);
- }
- // Address range to be distributed
- v->DhcpIpStart = IPToUINT(&vo->DhcpLeaseIPStart);
- v->DhcpIpEnd = IPToUINT(&vo->DhcpLeaseIPEnd);
- if (Endian32(v->DhcpIpEnd) < Endian32(v->DhcpIpStart))
- {
- v->DhcpIpEnd = v->DhcpIpStart;
- }
- // Subnet mask
- v->DhcpMask = IPToUINT(&vo->DhcpSubnetMask);
- // Gateway address
- v->DhcpGateway = IPToUINT(&vo->DhcpGatewayAddress);
- // DNS server address
- v->DhcpDns = IPToUINT(&vo->DhcpDnsServerAddress);
- v->DhcpDns2 = IPToUINT(&vo->DhcpDnsServerAddress2);
- // Domain name
- StrCpy(v->DhcpDomain, sizeof(v->DhcpDomain), vo->DhcpDomainName);
- // Save a log
- v->SaveLog = vo->SaveLog;
- // DHCP routing table pushing setting
- if (vo->ApplyDhcpPushRoutes)
- {
- DHCP_CLASSLESS_ROUTE_TABLE rt;
- Zero(&rt, sizeof(rt));
- if (ParseClasslessRouteTableStr(&rt, vo->DhcpPushRoutes))
- {
- Copy(&v->PushRoute, &rt, sizeof(DHCP_CLASSLESS_ROUTE_TABLE));
- }
- }
- }
- UnlockVirtual(v);
- }
- // Release the virtual host
- void Virtual_Free(VH *v)
- {
- // Release the DHCP server
- FreeDhcpServer(v);
- // NAT release
- FreeNat(v);
- LockVirtual(v);
- {
- // Release the IP combining list
- FreeIpCombineList(v);
- // Release the IP waiting table
- FreeIpWaitTable(v);
- // Release the ARP waiting table
- FreeArpWaitTable(v);
- // Release the ARP table
- FreeArpTable(v);
- // Release the transmission queue
- LockQueue(v->SendQueue);
- {
- BLOCK *block;
- // Release all queues
- while (block = GetNext(v->SendQueue))
- {
- FreeBlock(block);
- }
- }
- UnlockQueue(v->SendQueue);
- ReleaseQueue(v->SendQueue);
- v->SendQueue = NULL;
- // Release the cancel object
- ReleaseCancel(v->Cancel);
- v->Active = false;
- }
- UnlockVirtual(v);
- // Release the logger
- FreeLog(v->Logger);
- }
- void VirtualPaFree(SESSION *s)
- {
- VH *v;
- // Validate arguments
- if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
- {
- return;
- }
- Virtual_Free(v);
- }
- // Release the virtual host
- void ReleaseVirtual(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- if (Release(v->ref) == 0)
- {
- CleanupVirtual(v);
- }
- }
- // Lock the virtual host
- void LockVirtual(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- Lock(v->lock);
- }
- // Unlock the virtual host
- void UnlockVirtual(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- Unlock(v->lock);
- }
- // Cleanup the virtual host
- void CleanupVirtual(VH *v)
- {
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- if (v->Session != NULL)
- {
- ReleaseSession(v->Session);
- }
- DeleteCounter(v->Counter);
- DeleteLock(v->lock);
- Free(v);
- }
- // Stop the virtual host
- void StopVirtualHost(VH *v)
- {
- SESSION *s;
- // Validate arguments
- if (v == NULL)
- {
- return;
- }
- // Get the session corresponding to the virtual host
- LockVirtual(v);
- {
- s = v->Session;
- if (s != NULL)
- {
- AddRef(s->ref);
- }
- }
- UnlockVirtual(v);
- if (s == NULL)
- {
- // This session is already stopped
- return;
- }
- // Stop Session
- StopSession(s);
- ReleaseSession(s);
- }
- // Create a new virtual host
- VH *NewVirtualHost(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option)
- {
- return NewVirtualHostEx(cedar, option, auth, vh_option, NULL);
- }
- VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option, NAT *nat)
- {
- VH *v;
- SOCK *s;
- // Validate arguments
- if (vh_option == NULL)
- {
- return NULL;
- }
- // Create a VH
- v = ZeroMalloc(sizeof(VH));
- v->ref = NewRef();
- v->lock = NewLock();
- v->Counter = NewCounter();
- v->nat = nat;
- // Examine whether ICMP Raw Socket can be created
- s = NewUDP4(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4), NULL);
- if (s != NULL)
- {
- if (s->IsTtlSupported)
- {
- v->IcmpRawSocketOk = true;
- }
- ReleaseSock(s);
- }
- if (v->IcmpRawSocketOk == false)
- {
- if (IsIcmpApiSupported())
- {
- v->IcmpApiOk = true;
- }
- }
- // Set the options
- SetVirtualHostOption(v, vh_option);
- return v;
- }
- // Generate a random MAC address
- void GenMacAddress(UCHAR *mac)
- {
- UCHAR rand_data[32];
- UINT64 now;
- BUF *b;
- UCHAR hash[SHA1_SIZE];
- // Validate arguments
- if (mac == NULL)
- {
- return;
- }
- // Get the current time
- now = SystemTime64();
- // Generate a random number
- Rand(rand_data, sizeof(rand_data));
- // Add to the buffer
- b = NewBuf();
- WriteBuf(b, &now, sizeof(now));
- WriteBuf(b, rand_data, sizeof(rand_data));
- // Hash
- Hash(hash, b->Buf, b->Size, true);
- // Generate a MAC address
- mac[0] = 0x00;
- mac[1] = 0xAC; // AC hurray
- mac[2] = hash[0];
- mac[3] = hash[1];
- mac[4] = hash[2];
- mac[5] = hash[3];
- FreeBuf(b);
- }
- // Get a packet of virtual host adapter
- PACKET_ADAPTER *VirtualGetPacketAdapter()
- {
- return NewPacketAdapter(VirtualPaInit, VirtualPaGetCancel,
- VirtualPaGetNextPacket, VirtualPaPutPacket, VirtualPaFree);
- }
- // Developed by SoftEther VPN Project at University of Tsukuba in Japan.
- // Department of Computer Science has dozens of overly-enthusiastic geeks.
- // Join us: http://www.tsukuba.ac.jp/english/admission/
|