JFIFXX    $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222"4 ,PG"Z_4˷kjزZ,F+_z,© zh6٨icfu#ډb_N?wQ5-~I8TK<5oIv-k_U_~bMdӜUHh?]EwQk{_}qFW7HTՑYF?_'ϔ_Ջt=||I 6έ"D/[k9Y8ds|\Ҿp6Ҵ].6znopM[mei$[soᘨ˸ nɜG-ĨUycP3.DBli;hjx7Z^NhN3u{:jx힞#M&jL P@_ P&o89@Sz6t7#Oߋ s}YfTlmrZ)'Nk۞pw\Tȯ?8`Oi{wﭹW[r Q4F׊3m&L=h3z~#\l :F,j@ ʱwQT8"kJO6֚l}R>ډK]y&p}b;N1mr$|7>e@BTM*-iHgD) Em|ؘbҗaҾt4oG*oCNrPQ@z,|?W[0:n,jWiEW$~/hp\?{(0+Y8rΟ+>S-SVN;}s?. w9˟<Mq4Wv'{)01mBVW[8/< %wT^5b)iM pgN&ݝVO~qu9 !J27$O-! :%H ـyΠM=t{!S oK8txA& j0 vF Y|y ~6@c1vOpIg4lODL Rcj_uX63?nkWyf;^*B @~a`Eu+6L.ü>}y}_O6͐:YrGXkGl^w~㒶syIu! W XN7BVO!X2wvGRfT#t/?%8^WaTGcLMI(J1~8?aT ]ASE(*E} 2#I/׍qz^t̔bYz4xt){ OH+(EA&NXTo"XC')}Jzp ~5}^+6wcQ|LpdH}(.|kc4^"Z?ȕ a<L!039C EuCFEwç ;n?*oB8bʝ'#RqfM}7]s2tcS{\icTx;\7KPʇ Z O-~c>"?PEO8@8GQgaՎ󁶠䧘_%#r>1zaebqcPѵn#L =׀t L7`VA{C:ge@w1 Xp3c3ġpM"'-@n4fGB3DJ8[JoߐgK)ƛ$ 83+ 6ʻ SkI*KZlT _`?KQKdB`s}>`*>,*@JdoF*弝O}ks]yߘc1GV<=776qPTtXԀ!9*44Tހ3XΛex46YD  BdemDa\_l,G/֌7Y](xTt^%GE4}bTڹ;Y)BQu>J/J ⮶.XԄjݳ+Ed r5_D1 o Bx΢#<W8R6@gM. drD>(otU@x=~v2 ӣdoBd3eO6㣷ݜ66YQz`S{\P~z m5{J/L1xO\ZFu>ck#&:`$ai>2ΔloF[hlEܺΠk:)` $[69kOw\|8}ބ:񶐕IA1/=2[,!.}gN#ub ~݊}34qdELc$"[qU硬g^%B zrpJru%v\h1Yne`ǥ:gpQM~^Xi `S:V29.PV?Bk AEvw%_9CQwKekPؠ\;Io d{ ߞoc1eP\ `E=@KIRYK2NPlLɀ)&eB+ь( JTx_?EZ }@ 6U뙢طzdWIn` D噥[uV"G&Ú2g}&m?ċ"Om# {ON"SXNeysQ@FnVgdX~nj]J58up~.`r\O,ư0oS _Ml4kv\JSdxSW<AeIX$Iw:Sy›R9Q[,5;@]%u@ *rolbI  +%m:͇ZVủθau,RW33 dJeTYE.Mϧ-oj3+yy^cVO9NV\nd1 !͕_)av;թMlWR1)ElP;yوÏu 3k5Pr6<⒲l!˞*u־n!l:UNW %Chx8vL'X@*)̮ˍ D-M+JUkvK+x8cY?Ԡ~3mo|u@[XeYC\Kpx8oCC&N~3-H MXsu<`~"WL$8ξ3a)|:@m\^`@ҷ)5p+6p%i)P Mngc#0AruzRL+xSS?ʮ}()#tmˇ!0}}y$6Lt;$ʳ{^6{v6ķܰgVcnn ~zx«,2u?cE+ȘH؎%Za)X>uWTzNyosFQƤ$*&LLXL)1" LeOɟ9=:tZcŽY?ӭVwv~,Yrۗ|yGaFC.+ v1fήJ]STBn5sW}y$~z'c 8  ,! pVNSNNqy8z˱A4*'2n<s^ǧ˭PJޮɏUGLJ*#i}K%,)[z21z ?Nin1?TIR#m-1lA`fT5+ܐcq՝ʐ,3f2Uեmab#ŠdQy>\)SLYw#.ʑf ,"+w~N'cO3FN<)j&,- љ֊_zSTǦw>?nU仆Ve0$CdrP m׈eXmVu L.bֹ [Դaզ*\y8Է:Ez\0KqC b̘cөQ=0YsNS.3.Oo:#v7[#߫ 5܎LEr49nCOWlG^0k%;YߝZǓ:S#|}y,/kLd TA(AI$+I3;Y*Z}|ӧOdv..#:nf>>ȶITX 8y"dR|)0=n46ⲑ+ra ~]R̲c?6(q;5% |uj~z8R=XIV=|{vGj\gcqz؋%Mߍ1y#@f^^>N#x#۹6Y~?dfPO{P4Vu1E1J *|%JN`eWuzk M6q t[ gGvWIGu_ft5j"Y:Tɐ*; e54q$C2d} _SL#mYpO.C;cHi#֩%+) ӍƲVSYźg |tj38r|V1#;.SQA[S#`n+$$I P\[@s(EDzP])8G#0B[ىXIIq<9~[Z멜Z⊔IWU&A>P~#dp]9 "cP Md?٥Ifتuk/F9c*9Ǎ:ØFzn*@|Iށ9N3{'['ͬҲ4#}!V Fu,,mTIkv C7vB6kT91*l '~ƞFlU'M ][ΩũJ_{iIn$L jOdxkza۪#EClx˘oVɞljr)/,߬hL#^Lф,íMƁe̩NBLiLq}(q6IçJ$WE$:=#(KBzђ xlx?>Պ+>W,Ly!_DŌlQ![ SJ1ƐY}b,+Loxɓ)=yoh@꥟/Iѭ=Py9 ۍYӘe+pJnϱ?V\SO%(t =?MR[Șd/ nlB7j !;ӥ/[-A>dNsLj ,ɪv=1c.SQO3UƀܽE̻9GϷD7(}Ävӌ\y_0[w <΍>a_[0+LF.޺f>oNTq;y\bՃyjH<|q-eɏ_?_9+PHp$[uxK wMwNی'$Y2=qKBP~Yul:[<F12O5=d]Ysw:ϮEj,_QXz`H1,#II dwrP˂@ZJVy$\y{}^~[:NߌUOdؾe${p>G3cĖlʌ ת[`ϱ-WdgIig2 }s ؤ(%#sS@~3XnRG~\jc3vӍLM[JBTs3}jNʖW;7ç?=XF=-=qߚ#='c7ڑWI(O+=:uxqe2zi+kuGR0&eniT^J~\jyp'dtGsO39* b#Ɋ p[BwsT>d4ۧsnvnU_~,vƜJ1s QIz)(lv8MU=;56Gs#KMP=LvyGd}VwWBF'à ?MHUg2 !p7Qjڴ=ju JnA suMeƆҔ!)'8Ϣٔޝ(Vpצ֖d=ICJǠ{qkԭ߸i@Ku|p=..*+xz[Aqġ#s2aƊRR)*HRsi~a &fMP-KL@ZXy'x{}Zm+:)) IJ-iu ܒH'L(7yGӜq j 6ߌg1go,kرtY?W,pefOQS!K۟cҒA|սj>=⬒˧L[ ߿2JaB~Ru:Q] 0H~]7ƼI(}cq 'ήETq?fabӥvr )o-Q_'ᴎoK;Vo%~OK *bf:-ťIR`B5!RB@ï u ̯e\_U_ gES3QTaxU<~c?*#]MW,[8Oax]1bC|踤Plw5V%){t<d50iXSUm:Z┵i"1^B-PhJ&)O*DcWvM)}Pܗ-q\mmζZ-l@}aE6F@&Sg@ݚM ȹ 4#p\HdYDoH"\..RBHz_/5˘6KhJRPmƶim3,#ccoqa)*PtRmk7xDE\Y閣_X<~)c[[BP6YqS0%_;Àv~| VS؇ 'O0F0\U-d@7SJ*z3nyPOm~P3|Yʉr#CSN@ ƮRN)r"C:: #qbY. 6[2K2uǦHYRQMV G$Q+.>nNHq^ qmMVD+-#*U̒ p욳u:IBmPV@Or[b= 1UE_NmyKbNOU}the`|6֮P>\2PVIDiPO;9rmAHGWS]J*_G+kP2KaZH'KxWMZ%OYDRc+o?qGhmdSoh\D|:WUAQc yTq~^H/#pCZTI1ӏT4"ČZ}`w#*,ʹ 0i課Om*da^gJ݅{le9uF#Tֲ̲ٞC"qߍ ոޑo#XZTp@ o8(jdxw],f`~|,s^f1t|m򸄭/ctr5s79Q4H1꠲BB@l9@C+wpxu£Yc9?`@#omHs2)=2.ljg9$YS%*LRY7Z,*=䷘$armoϰUW.|rufIGwtZwo~5 YյhO+=8fF)W7L9lM̘·Y֘YLf큹pRF99.A "wz=E\Z'a 2Ǚ#;'}G*l^"q+2FQ hjkŦ${ޮ-T٭cf|3#~RJt$b(R(rdx >U b&9,>%E\ Άe$'q't*אެb-|dSBOO$R+H)܎K1m`;J2Y~9Og8=vqD`K[F)k[1m޼cn]skz$@)!I x՝"v9=ZA=`Ɠi :E)`7vI}dYI_ o:obo 3Q&D&2= Ά;>hy.*ⅥSӬ+q&j|UƧ}J0WW< ۋS)jQRjƯrN)Gű4Ѷ(S)Ǣ8iW52No˓ ۍ%5brOnL;n\G=^UdI8$&h'+(cȁ߫klS^cƗjԌEꭔgFȒ@}O*;evWVYJ\]X'5ղkFb 6Ro՜mi Ni>J?lPmU}>_Z&KKqrIDՉ~q3fL:Se>E-G{L6pe,8QIhaXaUA'ʂs+טIjP-y8ۈZ?J$WP Rs]|l(ԓsƊio(S0Y 8T97.WiLc~dxcE|2!XKƘਫ਼$((6~|d9u+qd^389Y6L.I?iIq9)O/뚅OXXVZF[یgQLK1RҖr@v#XlFНyS87kF!AsM^rkpjPDyS$Nqnxҍ!Uf!ehi2m`YI9r6 TFC}/y^Η5d'9A-J>{_l+`A['յϛ#w:݅%X}&PStQ"-\縵/$ƗhXb*yBS;Wջ_mcvt?2}1;qSdd~u:2k52R~z+|HE!)Ǟl7`0<,2*Hl-x^'_TVgZA'j ^2ΪN7t?w x1fIzC-ȖK^q;-WDvT78Z hK(P:Q- 8nZ܃e貾<1YT<,"6{/ ?͟|1:#gW>$dJdB=jf[%rE^il:BxSּ1հ,=*7 fcG#q eh?27,!7x6nLC4x},GeǝtC.vS F43zz\;QYC,6~;RYS/6|25vTimlv& nRh^ejRLGf? ۉҬܦƩ|Ȱ>3!viʯ>vオX3e_1zKȗ\qHS,EW[㺨uch⍸O}a>q6n6N6qN ! 1AQaq0@"2BRb#Pr3C`Scst$4D%Td ?Na3mCwxAmqmm$4n淿t'C"wzU=D\R+wp+YT&պ@ƃ3ޯ?AﶂaŘ@-Q=9Dռѻ@MVP܅G5fY6# ?0UQ,IX(6ڵ[DIMNލc&υj\XR|,4 jThAe^db#$]wOӪ1y%LYm뭛CUƃߜ}Cy1XνmF8jI]HۺиE@Ii;r8ӭVFՇ| &?3|xBMuSGe=Ӕ#BE5GY!z_eqр/W>|-Ci߇t1ޯќdR3ug=0 5[?#͏qcfH{ ?u=??ǯ}ZzhmΔBFTWPxs}G93 )gGR<>r h$'nchPBjJҧH -N1N?~}-q!=_2hcMlvY%UE@|vM2.Y[|y"EïKZF,ɯ?,q?vM 80jx";9vk+ ֧ ȺU?%vcVmA6Qg^MA}3nl QRNl8kkn'(M7m9وq%ޟ*h$Zk"$9: ?U8Sl,,|ɒxH(ѷGn/Q4PG%Ա8N! &7;eKM749R/%lc>x;>C:th?aKXbheᜋ^$Iհ hr7%F$EFdt5+(M6tÜUU|zW=aTsTgdqPQb'm1{|YXNb P~F^F:k6"j! Ir`1&-$Bevk:y#ywI0x=D4tUPZHڠ底taP6b>xaQ# WeFŮNjpJ* mQN*I-*ȩFg3 5Vʊɮa5FO@{NX?H]31Ri_uѕ 0 F~:60p͈SqX#a5>`o&+<2D: ڝ$nP*)N|yEjF5ټeihyZ >kbHavh-#!Po=@k̆IEN@}Ll?jO߭ʞQ|A07xwt!xfI2?Z<ץTcUj]陎Ltl }5ϓ$,Omˊ;@OjEj(ا,LXLOЦ90O .anA7j4 W_ٓzWjcBy՗+EM)dNg6y1_xp$Lv:9"zpʙ$^JԼ*ϭo=xLj6Ju82AH3$ٕ@=Vv]'qEz;I˼)=ɯx /W(Vp$ mu񶤑OqˎTr㠚xsrGCbypG1ߠw e8$⿄/M{*}W]˷.CK\ުx/$WPwr |i&}{X >$-l?-zglΆ(FhvS*b߲ڡn,|)mrH[a3ר[13o_U3TC$(=)0kgP u^=4 WYCҸ:vQרXàtkm,t*^,}D* "(I9R>``[~Q]#afi6l86:,ssN6j"A4IuQ6E,GnHzSHOuk5$I4ؤQ9@CwpBGv[]uOv0I4\yQѸ~>Z8Taqޣ;za/SI:ܫ_|>=Z8:SUIJ"IY8%b8H:QO6;7ISJҌAά3>cE+&jf$eC+z;V rʺmyeaQf&6ND.:NTvm<- uǝ\MvZYNNT-A>jr!SnO 13Ns%3D@`ܟ 1^c< aɽ̲Xë#w|ycW=9I*H8p^(4՗karOcWtO\ƍR8'KIQ?5>[}yUײ -h=% qThG2)"ו3]!kB*pFDlA,eEiHfPs5H:Փ~H0DتDIhF3c2E9H5zԑʚiX=:mxghd(v׊9iSOd@0ڽ:p5h-t&Xqӕ,ie|7A2O%PEhtjY1wЃ!  ࢽMy7\a@ţJ 4ȻF@o̒?4wx)]P~u57X 9^ܩU;Iꭆ 5 eK27({|Y׎ V\"Z1 Z}(Ǝ"1S_vE30>p; ΝD%xW?W?vo^Vidr[/&>~`9Why;R ;;ɮT?r$g1KACcKl:'3 cﳯ*"t8~l)m+U,z`(>yJ?h>]vЍG*{`;y]IT ;cNUfo¾h/$|NS1S"HVT4uhǜ]v;5͠x'C\SBplh}N ABx%ޭl/Twʽ]D=Kžr㻠l4SO?=k M: cCa#ha)ѐxcsgPiG{+xQI= zԫ+ 8"kñj=|c yCF/*9жh{ ?4o kmQNx;Y4膚aw?6>e]Qr:g,i"ԩA*M7qB?ӕFhV25r[7 Y }LR}*sg+xr2U=*'WSZDW]WǞ<叓{$9Ou4y90-1'*D`c^o?(9uݐ'PI& fJݮ:wSjfP1F:X H9dԯ˝[_54 }*;@ܨ ðynT?ןd#4rGͨH1|-#MrS3G3).᧏3vz֑r$G"`j 1tx0<ƆWh6y6,œGagAyb)hDß_mü gG;evݝnQ C-*oyaMI><]obD":GA-\%LT8c)+y76oQ#*{(F⽕y=rW\p۩cA^e6KʐcVf5$'->ՉN"F"UQ@fGb~#&M=8טJNu9D[̤so~ G9TtW^g5y$bY'سǴ=U-2 #MCt(i lj@Q 5̣i*OsxKf}\M{EV{υƇ);HIfeLȣr2>WIȂ6ik 5YOxȺ>Yf5'|H+98pjn.OyjY~iw'l;s2Y:'lgꥴ)o#'SaaKZ m}`169n"xI *+ }FP"l45'ZgE8?[X7(.Q-*ތL@̲v.5[=t\+CNܛ,gSQnH}*FG16&:t4ُ"Ạ$b |#rsaT ]ӽDP7ո0y)e$ٕvIh'QEAm*HRI=: 4牢) %_iNݧl] NtGHL ɱg<1V,J~ٹ"KQ 9HS9?@kr;we݁]I!{ @G["`J:n]{cAEVʆ#U96j#Ym\qe4hB7Cdv\MNgmAyQL4uLjj9#44tl^}LnR!t±]rh6ٍ>yҏNfU  Fm@8}/ujb9he:AyծwGpΧh5l}3p468)Udc;Us/֔YX1O2uqs`hwgr~{ RmhN؎*q 42*th>#E#HvOq}6e\,Wk#Xb>p}դ3T5†6[@Py*n|'f֧>lư΂̺SU'*qp_SM 'c6m ySʨ;MrƋmKxo,GmPAG:iw9}M(^V$ǒѽ9| aJSQarB;}ٻ֢2%Uc#gNaݕ'v[OY'3L3;,p]@S{lsX'cjwk'a.}}& dP*bK=ɍ!;3ngΊUߴmt'*{,=SzfD Ako~Gaoq_mi}#mPXhύmxǍ΂巿zfQc|kc?WY$_Lvl߶c`?ljݲˏ!V6UЂ(A4y)HpZ_x>eR$/`^'3qˏ-&Q=?CFVR DfV9{8gnh(P"6[D< E~0<@`G6Hгcc cK.5DdB`?XQ2ٿyqo&+1^ DW0ꊩG#QnL3c/x 11[yxპCWCcUĨ80me4.{muI=f0QRls9f9~fǨa"@8ȁQ#cicG$Gr/$W(WV"m7[mAmboD j۳ l^kh׽ # iXnveTka^Y4BNĕ0 !01@Q"2AaPq3BR?@4QT3,㺠W[=JKϞ2r^7vc:9 EߴwS#dIxu:Hp9E! V 2;73|F9Y*ʬFDu&y؟^EAA(ɩ^GV:ݜDy`Jr29ܾ㝉[E;FzxYGUeYC v-txIsםĘqEb+P\ :>iC';k|zرny]#ǿbQw(r|ӹs[D2v-%@;8<a[\o[ϧwI!*0krs)[J9^ʜp1) "/_>o<1AEy^C`x1'ܣnps`lfQ):lb>MejH^?kl3(z:1ŠK&?Q~{ٺhy/[V|6}KbXmn[-75q94dmc^h X5G-}دBޟ |rtMV+]c?-#ڛ^ǂ}LkrOu>-Dry D?:ޞUǜ7V?瓮"#rչģVR;n/_ ؉vݶe5db9/O009G5nWJpA*r9>1.[tsFnQ V 77R]ɫ8_0<՜IFu(v4Fk3E)N:yڮeP`1}$WSJSQNjٺ޵#lј(5=5lǏmoWv-1v,Wmn߀$x_DȬ0¤#QR[Vkzmw"9ZG7'[=Qj8R?zf\a=OU*oBA|G254 p.w7  &ξxGHp B%$gtЏ򤵍zHNuЯ-'40;_3 !01"@AQa2Pq#3BR?ʩcaen^8F<7;EA{EÖ1U/#d1an.1ě0ʾRh|RAo3m3 % 28Q yφHTo7lW>#i`qca m,B-j݋'mR1Ήt>Vps0IbIC.1Rea]H64B>o]($Bma!=?B KǾ+Ծ"nK*+[T#{EJSQs5:U\wĐf3܆&)IԆwE TlrTf6Q|Rh:[K zc֧GC%\_a84HcObiؖV7H )*ģK~Xhչ04?0 E<}3#u? |gS6ꊤ|I#Hڛ աwX97Ŀ%SLy6č|Fa 8b$sקhb9RAu7˨pČ_\*w묦F 4D~f|("mNKiS>$d7SlA/²SL|6N}S˯g]6; #. 403WebShell
403Webshell
Server IP : 45.32.152.128  /  Your IP : 216.73.216.91
Web Server : nginx/1.24.0
System : Linux stage-vultr 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
User : forge ( 1000)
PHP Version : 8.2.14
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/share/nmap/nselib/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/share/nmap/nselib/packet.lua
---
-- Facilities for manipulating raw packets.
--
-- @author Marek Majkowski <majek04+nse@gmail.com>
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html

local ipOps = require "ipOps"
local stdnse = require "stdnse"
local string = require "string"
_ENV = stdnse.module("packet", stdnse.seeall)


----------------------------------------------------------------------------------------------------------------
--- Get an 8-bit integer at a 0-based byte offset in a byte string.
-- @param b A byte string.
-- @param i Offset.
-- @return An 8-bit integer.
function u8(b, i)
  return string.byte(b, i+1)
end
--- Get a 16-bit integer at a 0-based byte offset in a byte string.
-- @param b A byte string.
-- @param i Offset.
-- @return A 16-bit integer.
function u16(b, i)
  local b1,b2
  b1, b2 = string.byte(b, i+1), string.byte(b, i+2)
  --        2^8     2^0
  return b1*256 + b2
end
--- Get a 32-bit integer at a 0-based byte offset in a byte string.
-- @param b A byte string.
-- @param i Offset.
-- @return A 32-bit integer.
function u32(b,i)
  local b1,b2,b3,b4
  b1, b2 = string.byte(b, i+1), string.byte(b, i+2)
  b3, b4 = string.byte(b, i+3), string.byte(b, i+4)
  --        2^24          2^16       2^8     2^0
  return b1*16777216 + b2*65536 + b3*256 + b4
end

--- Set an 8-bit integer at a 0-based byte offset in a byte string
-- (big-endian).
-- @param b A byte string.
-- @param i Offset.
-- @param num Integer to store.
function set_u8(b, i, num)
  local s = string.char(num & 0xff)
  return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+1)
end
--- Set a 16-bit integer at a 0-based byte offset in a byte string
-- (big-endian).
-- @param b A byte string.
-- @param i Offset.
-- @param num Integer to store.
function set_u16(b, i, num)
  local s = string.char((num >> 8) & 0xff) .. string.char(num & 0xff)
  return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+2)
end
--- Set a 32-bit integer at a 0-based byte offset in a byte string
-- (big-endian).
-- @param b A byte string.
-- @param i Offset.
-- @param num Integer to store.
function set_u32(b,i, num)
  local s = string.char((num >> 24) & 0xff) ..
  string.char((num >>16) & 0xff) ..
  string.char((num >> 8) & 0xff) ..
  string.char(num & 0xff)
  return b:sub(0+1, i+1-1) .. s .. b:sub(i+1+4)
end
--- Get a 1-byte string from a number.
-- @param num A number.
function numtostr8(num)
  return string.char(num)
end
--- Get a 2-byte string from a number.
-- (big-endian)
-- @param num A number.
function numtostr16(num)
  return set_u16("..", 0, num)
end
--- Get a 4-byte string from a number.
-- (big-endian)
-- @param num A number.
function numtostr32(num)
  return set_u32("....", 0, num)
end

--- Calculate a standard Internet checksum.
-- @param b Data to checksum.
-- @return Checksum.
function in_cksum(b)
  local sum = 0
  local i

  -- Note we are using 0-based indexes here.
  i = 0
  while i < b:len() - 1 do
    sum = sum + u16(b, i)
    i = i + 2
  end
  if i < b:len() then
    sum = sum + u8(b, i) * 256
  end

  sum = (sum >> 16) + (sum & 0xffff)
  sum = sum + (sum >> 16)
  sum = ~sum
  sum = (sum & 0xffff) -- truncate to 16 bits
  return sum
end

-- ip protocol field
IPPROTO_IP   = 0      --  Dummy protocol for TCP
IPPROTO_HOPOPTS = 0   --  IPv6 hop-by-hop options
IPPROTO_ICMP = 1      --  Internet Control Message Protocol
IPPROTO_IGMP = 2      --  Internet Group Management Protocol
IPPROTO_IPIP = 4      --  IPIP tunnels (older KA9Q tunnels use 94)
IPPROTO_TCP  = 6      --  Transmission Control Protocol
IPPROTO_EGP  = 8      --  Exterior Gateway Protocol
IPPROTO_PUP  = 12     --  PUP protocol
IPPROTO_UDP  = 17     --  User Datagram Protocol
IPPROTO_IDP  = 22     --  XNS IDP protocol
IPPROTO_DCCP = 33     --  Datagram Congestion Control Protocol
IPPROTO_RSVP = 46     --  RSVP protocol
IPPROTO_GRE  = 47     --  Cisco GRE tunnels (rfc 1701,1702)
IPPROTO_IPV6 = 41     --  IPv6-in-IPv4 tunnelling

IPPROTO_ROUTING = 43  --  IPv6 routing header
IPPROTO_FRAGMENT= 44  --  IPv6 fragmentation header
IPPROTO_ESP     = 50  --  Encapsulation Security Payload protocol
IPPROTO_AH      = 51  --  Authentication Header protocol
IPPROTO_ICMPV6  = 58  --  ICMP for IPv6
IPPROTO_DSTOPTS = 60  --  IPv6 destination options
IPPROTO_BEETPH  = 94  --  IP option pseudo header for BEET
IPPROTO_PIM     = 103 --  Protocol Independent Multicast

IPPROTO_COMP    = 108 --  Compression Header protocol
IPPROTO_SCTP    = 132 --  Stream Control Transport Protocol
IPPROTO_UDPLITE = 136 --  UDP-Lite (RFC 3828)


ICMP_ECHO_REQUEST   = 8
ICMP_ECHO_REPLY     = 0

ICMP6_ECHO_REQUEST = 128
ICMP6_ECHO_REPLY = 129
MLD_LISTENER_QUERY = 130
MLD_LISTENER_REPORT = 131
MLD_LISTENER_REDUCTION = 132
ND_ROUTER_SOLICIT = 133
ND_ROUTER_ADVERT = 134
ND_NEIGHBOR_SOLICIT = 135
ND_NEIGHBOR_ADVERT = 136
ND_REDIRECT = 137
MLDV2_LISTENER_REPORT = 143

ND_OPT_SOURCE_LINKADDR = 1
ND_OPT_TARGET_LINKADDR = 2
ND_OPT_PREFIX_INFORMATION = 3
ND_OPT_REDIRECTED_HEADER = 4
ND_OPT_MTU = 5
ND_OPT_RTR_ADV_INTERVAL = 7
ND_OPT_HOME_AGENT_INFO = 8

ETHER_TYPE_IPV4 = "\x08\x00"
ETHER_TYPE_IPV6 = "\x86\xdd"

----------------------------------------------------------------------------------------------------------------
-- Frame is a class
Frame = {}

function Frame:new(frame, force_continue)
  local packet = nil
  local packet_len = 0
  if frame and #frame > 14 then
    packet = string.sub(frame, 15, -1)
    packet_len = #frame - 14
  end
  local o = Packet:new(packet, packet_len, force_continue)

  o.build_ether_frame = self.build_ether_frame
  o.ether_parse = self.ether_parse
  o.frame_buf = frame
  o:ether_parse()
  return o
end
--- Build an Ethernet frame.
-- @param mac_dst six-byte string of the destination MAC address.
-- @param mac_src six-byte string of the source MAC address.
-- @param ether_type two-byte string of the type.
-- @param packet string of the payload.
-- @return frame string of the Ether frame.
function Frame:build_ether_frame(mac_dst, mac_src, ether_type, packet)
  self.mac_dst = mac_dst or self.mac_dst
  self.mac_src = mac_src or self.mac_src
  self.ether_type = ether_type or self.ether_type
  self.buf = packet or self.buf
  if not self.ether_type then
    return nil, "Unknown packet type."
  end
  self.frame_buf = self.mac_dst..self.mac_src..self.ether_type..self.buf
end
--- Parse an Ethernet frame.
-- @param frame string of the Ether frame.
-- @return mac_dst six-byte string of the destination MAC address.
-- @return mac_src six-byte string of the source MAC address.
-- @return packet string of the payload.
function Frame:ether_parse()
  if not self.frame_buf or #self.frame_buf < 14 then -- too short
    return false
  end
  self.mac_dst = string.sub(self.frame_buf, 1, 6)
  self.mac_src = string.sub(self.frame_buf, 7, 12)
  self.ether_type = u16(self.frame_buf, 12)
end

----------------------------------------------------------------------------------------------------------------
-- Packet is a class
Packet = {}

--- Create a new Packet object.
-- @param packet Binary string with packet data.
-- @param packet_len Packet length. It could be more than
-- <code>#packet</code>.
-- @param force_continue whether an error in parsing headers should be fatal or
-- not. This is especially useful when parsing ICMP packets, where a small ICMP
-- payload could be a TCP header. The problem is that parsing this payload
-- normally would fail because the TCP header is too small.
-- @return A new Packet.
function Packet:new(packet, packet_len, force_continue)
  local o = setmetatable({}, {__index = Packet})
  if not packet then
    return o
  end
  o.buf = packet
  o.packet_len = packet_len
  o.ip_v = string.byte(o.buf) >> 4
  if o.ip_v == 4 and not o:ip_parse(force_continue) then
    return nil
  elseif o.ip_v == 6 and not o:ip6_parse(force_continue) then
    return nil
  end

  if o.ip_v == 6 then
    while o:ipv6_is_extension_header() do
      if not o:ipv6_ext_header_parse(force_continue) or o.ip6_data_offset >= o.packet_len then
        stdnse.debug1("Error while parsing IPv6 extension headers.")
        return o
      end
    end
    o.ip_p = o.ip6_nhdr
  end

  if o.ip_p == IPPROTO_TCP then
    if not o:tcp_parse(force_continue) then
      stdnse.debug1("Error while parsing TCP packet\n")
    end
  elseif o.ip_p == IPPROTO_UDP then
    if not o:udp_parse(force_continue) then
      stdnse.debug1("Error while parsing UDP packet\n")
    end
  elseif o.ip_p == IPPROTO_ICMP then
    if not o:icmp_parse(force_continue) then
      stdnse.debug1("Error while parsing ICMP packet\n")
    end
  elseif o.ip_p == IPPROTO_ICMPV6 then
    if not o:icmpv6_parse(force_continue) then
      stdnse.debug1("Error while parsing ICMPv6 packet\n")
    end
  end
  return o
end
--- Convert Version, Traffic Class and Flow Label to a 4-byte string.
-- @param ip6_tc Number stands for Traffic Class.
-- @param ip6_fl Number stands for Flow Label.
-- @return The first four-byte string of an IPv6 header.
function ipv6_hdr_pack_tc_fl(ip6_tc, ip6_fl)
  local ver_tc_fl = (6 << 28) +
    ((ip6_tc & 0xFF) << 20) +
    (ip6_fl & 0xFFFFF)
  return numtostr32(ver_tc_fl)
end
--- Build an IPv6 packet.
-- @param src 16-byte string of the source IPv6 address.
-- @param dsr 16-byte string of the destination IPv6 address.
-- @param nx_hdr integer that represents next header.
-- @param h_limit integer that represents hop limit.
-- @param t_class integer that represents traffic class.
-- @param f_label integer that represents flow label.
function Packet:build_ipv6_packet(src, dst, nx_hdr, payload, h_limit, t_class, f_label)
  self.ether_type = ETHER_TYPE_IPV6
  self.ip_v = 6
  self.ip_bin_src = src or self.ip_bin_src
  self.ip_bin_dst = dst or self.ip_bin_dst
  self.ip6_nhdr = nx_hdr or self.ip6_nhdr
  self.l4_packet = payload or self.l4_packet
  self.ip6_tc = t_class or self.ip6_tc or 1
  self.ip6_fl = f_label or self.ip6_fl or 1
  self.ip6_hlimit = h_limit or self.ip6_hlimit or 255
  self.ip6_plen = #(self.exheader or "")+#(self.l4_packet or "")
  self.buf =
    ipv6_hdr_pack_tc_fl(self.ip6_tc, self.ip6_fl) ..
    numtostr16(self.ip6_plen) .. --payload length
    string.char(self.ip6_nhdr) .. --next header
    string.char(self.ip6_hlimit) .. --hop limit
    self.ip_bin_src .. --Source
    self.ip_bin_dst ..--dest
    (self.exheader or "")..
    (self.l4_packet or "")
end
--- Return true if and only if the next header is an known extension header.
-- @param nhdr Next header.
function Packet:ipv6_is_extension_header(nhdr)
  self.ip6_nhdr = nhdr or self.ip6_nhdr
  if self.ip6_nhdr == IPPROTO_HOPOPTS or
    self.ip6_nhdr == IPPROTO_DSTOPTS or
    self.ip6_nhdr == IPPROTO_ROUTING or
    self.ip6_nhdr == IPPROTO_FRAGMENT then
    return true
  end
  return nil
end
--- Count IPv6 checksum.
-- @return the checksum.
function Packet:count_ipv6_pseudoheader_cksum()
  local pseudoheader = self.ip_bin_src .. self.ip_bin_dst .. numtostr16(#self.l4_packet) .. "\0\0\0" .. string.char(self.ip6_nhdr)
  local ck_content = pseudoheader .. self.l4_packet
  return in_cksum(ck_content)
end
--- Set ICMPv6 checksum.
function Packet:set_icmp6_cksum(check_sum)
  self.l4_packet = set_u16(self.l4_packet, 2, check_sum)
end
--- Build an ICMPv6 header.
-- @param icmpv6_type integer that represent ICMPv6 type.
-- @param icmpv6_code integer that represent ICMPv6 code.
-- @param icmpv6_payload string of the payload
-- @param ip_bin_src 16-byte string of the source IPv6 address.
-- @param ip_bin_dst 16-byte string of the destination IPv6 address.
function Packet:build_icmpv6_header(icmpv6_type, icmpv6_code, icmpv6_payload, ip_bin_src, ip_bin_dst)
  self.ip6_nhdr = IPPROTO_ICMPV6
  self.icmpv6_type = icmpv6_type or self.icmpv6_type
  self.icmpv6_code = icmpv6_code or self.icmpv6_code
  self.icmpv6_payload = icmpv6_payload or self.icmpv6_payload
  self.ip_bin_src = ip_bin_src or self.ip_bin_src
  self.ip_bin_dst = ip_bin_dst or self.ip_bin_dst

  self.l4_packet =
    string.char(self.icmpv6_type,self.icmpv6_code) ..
    "\0\0" .. --checksum
    (self.icmpv6_payload or "")
  local check_sum = self:count_ipv6_pseudoheader_cksum()
  self:set_icmp6_cksum(check_sum)
end
--- Build an ICMPv6 Echo Request frame.
-- @param mac_src six-byte string of source MAC address.
-- @param mac_dst sis-byte string of destination MAC address.
-- @param ip_bin_src 16-byte string of source IPv6 address.
-- @param ip_bin_dst 16-byte string of destination IPv6 address.
-- @param id integer that represents Echo ID.
-- @param sequence integer that represents Echo sequence.
-- @param data string of Echo data.
-- @param tc integer that represents traffic class of IPv6 packet.
-- @param fl integer that represents flow label of IPv6 packet.
-- @param hop-limit integer that represents hop limit of IPv6 packet.
function Packet:build_icmpv6_echo_request(id, sequence, data, mac_src, mac_dst, ip_bin_src, ip_bin_dst, tc, fl, hop_limit)
  self.mac_src = mac_src or self.mac_src
  self.mac_dst = mac_dst or self.mac_dst

  self.ip_bin_src = ip_bin_src or self.ip_bin_src
  self.ip_bin_dst = ip_bin_dst or self.ip_bin_dst
  self.traffic_class = tc or 1
  self.flow_label = fl or 1
  self.ip6_hlimit = hop_limit or 255

  self.icmpv6_type = ICMP6_ECHO_REQUEST
  self.icmpv6_code = 0

  self.echo_id = id or self.echo_id or 0xdead
  self.echo_seq = sequence or self.echo_seq or 0xbeef
  self.echo_data = data or self.echo_data or ""

  self.icmpv6_payload = numtostr16(self.echo_id) .. numtostr16(self.echo_seq) .. self.echo_data
end
--- Set an ICMPv6 option message.
function Packet:set_icmpv6_option(opt_type,msg)
  return string.char(opt_type, (#msg+2)/8) .. msg
end

--- Build an IPv4 packet.
-- @param src 4-byte string of the source IP address.
-- @param dst 4-byte string of the destination IP address.
-- @param payload string containing the IP payload
-- @param dsf byte that represents the differentiated services field
-- @param id integer that represents the IP identification
-- @param flags integer that represents the IP flags
-- @param off integer that represents the IP offset
-- @param ttl integer that represent the IP time to live
-- @param proto integer that represents the IP protocol
function Packet:build_ip_packet(src, dst, payload, dsf, id, flags, off, ttl, proto)
  self.ether_type = ETHER_TYPE_IPV4
  self.ip_v = 4
  self.ip_bin_src = src or self.ip_bin_src
  self.ip_bin_dst = dst or self.ip_bin_dst
  self.l3_packet = payload or self.l3_packet
  self.ip_dsf = dsf or self.ip_dsf or 0
  self.ip_p = proto or self.ip_p
  self.flags = flags or self.flags or 0 -- should be split into ip_rd, ip_df, ip_mv
  self.ip_id = id or self.ip_id or 0xbeef
  self.ip_off = off or self.ip_off or 0
  self.ip_ttl = ttl or self.ip_ttl or 255
  self.buf =
    numtostr8((self.ip_v << 4) + 20 / 4) .. -- version and header length
    numtostr8(self.ip_dsf) ..
    numtostr16(#self.l3_packet + 20) ..
    numtostr16(self.ip_id) ..
    numtostr8(self.flags) ..
    numtostr8(self.ip_off) ..
    numtostr8(self.ip_ttl) ..
    numtostr8(self.ip_p) ..
    numtostr16(0) .. -- checksum
    self.ip_bin_src ..  --Source
    self.ip_bin_dst --dest

  self.buf = set_u16(self.buf, 10, in_cksum(self.buf))
  self.buf = self.buf .. self.l3_packet
end
--- Build an ICMP header.
-- @param icmp_type integer that represent ICMPv6 type.
-- @param icmp_code integer that represent ICMPv6 code.
-- @param icmp_payload string of the payload
-- @param ip_bin_src 16-byte string of the source IPv6 address.
-- @param ip_bin_dst 16-byte string of the destination IPv6 address.
function Packet:build_icmp_header(icmp_type, icmp_code, icmp_payload, ip_bin_src, ip_bin_dst)
  self.icmp_type = icmp_type or self.icmp_type
  self.icmp_code = icmp_code or self.icmp_code
  self.icmp_payload = icmp_payload or self.icmp_payload
  self.ip_bin_src = ip_bin_src or self.ip_bin_src
  self.ip_bin_dst = ip_bin_dst or self.ip_bin_dst

  self.l3_packet =
  string.char(self.icmp_type,self.icmp_code) ..
  "\0\0" .. --checksum
  (self.icmp_payload or "")
  self.l3_packet = set_u16(self.l3_packet, 2, in_cksum(self.l3_packet))
end
--- Build an ICMP Echo Request frame.
-- @param mac_src six-byte string of source MAC address.
-- @param mac_dst sis-byte string of destination MAC address.
-- @param ip_bin_src 16-byte string of source IPv6 address.
-- @param ip_bin_dst 16-byte string of destination IPv6 address.
-- @param id integer that represents Echo ID.
-- @param seq integer that represents Echo sequence.
-- @param data string of Echo data.
-- @param dsf integer that represents differentiated services field.
function Packet:build_icmp_echo_request(id, seq, data, mac_src, mac_dst, ip_bin_src, ip_bin_dst)
  self.mac_src = mac_src or self.mac_src
  self.mac_dst = mac_dst or self.mac_dst

  self.ip_p = IPPROTO_ICMP
  self.ip_bin_src = ip_bin_src or self.ip_bin_src
  self.ip_bin_dst = ip_bin_dst or self.ip_bin_dst

  self.icmp_type = ICMP_ECHO_REQUEST
  self.icmp_code = 0

  self.echo_id = id or self.echo_id or 0xdead
  self.echo_seq = seq or self.echo_seq or 0xbeef
  self.echo_data = data or self.echo_data or ""

  self.icmp_payload = numtostr16(self.echo_id) .. numtostr16(self.echo_seq) .. self.echo_data
end


-- Helpers


--- Convert a MAC address string (like <code>"00:23:ae:5d:3b:10"</code>) to
-- a raw six-byte long.
-- @param str MAC address string.
-- @return Six-byte string.
function mactobin(str)
  if not str then
    return nil, "MAC was not specified."
  end
  return (str:gsub("(%x%x)[^%x]?", function (x)
        return string.char(tonumber(x, 16))
    end))
end

--- Generate the link-local IPv6 address from the MAC address.
-- @param mac  MAC address string.
-- @return Link-local IPv6 address string.
function mac_to_lladdr(mac)
  if not mac then
    return nil, "MAC was not specified."
  end
  local interfier = string.char((string.byte(mac,1) | 0x02))..string.sub(mac,2,3).."\xff\xfe"..string.sub(mac,4,6)
  local ll_prefix = ipOps.ip_to_str("fe80::")
  return string.sub(ll_prefix,1,8)..interfier
end
--- Get an 8-bit integer at a 0-based byte offset in the packet.
-- @param index Offset.
-- @return An 8-bit integer.
function Packet:u8(index)
  return u8(self.buf, index)
end
--- Get a 16-bit integer at a 0-based byte offset in the packet.
-- @param index Offset.
-- @return A 16-bit integer.
function Packet:u16(index)
  return u16(self.buf, index)
end
--- Get a 32-bit integer at a 0-based byte offset in the packet.
-- @param index Offset.
-- @return An 32-bit integer.
function Packet:u32(index)
  return u32(self.buf, index)
end
--- Return part of the packet contents as a byte string.
-- @param index The beginning of the part of the packet to extract. The index
-- is 0-based. If omitted the default value is 0 (beginning of the string)
-- @param length The length of the part of the packet to extract. If omitted
-- the remaining contents from index to the end of the string are returned.
-- @return A string.
function Packet:raw(index, length)
  if not index then index = 0 end
  if not length then length = #self.buf-index end
  return string.char(string.byte(self.buf, index+1, index+1+length-1))
end

--- Set an 8-bit integer at a 0-based byte offset in the packet.
-- (big-endian).
-- @param index Offset.
-- @param num Integer to store.
function Packet:set_u8(index, num)
  self.buf = set_u8(self.buf, index, num)
  return self.buf
end
--- Set a 16-bit integer at a 0-based byte offset in the packet.
-- (big-endian).
-- @param index Offset.
-- @param num Integer to store.
function Packet:set_u16(index, num)
  self.buf = set_u16(self.buf, index, num)
  return self.buf
end
--- Set a 32-bit integer at a 0-based byte offset in the packet.
-- (big-endian).
-- @param index Offset.
-- @param num Integer to store.
function Packet:set_u32(index, num)
  self.buf = set_u32(self.buf, index, num)
  return self.buf
end

--- Parse an IP packet header.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:ip_parse(force_continue)
  self.ip_offset = 0
  if    #self.buf < 20 then -- too short
    print("too short")
    return false
  end
  self.ip_v = (self:u8(self.ip_offset + 0) & 0xF0) >> 4
  self.ip_hl = (self:u8(self.ip_offset + 0) & 0x0F) -- header_length or data_offset
  if    self.ip_v ~= 4 then -- not ip
    print("not v4")
    return false
  end
  self.ip = true
  self.ip_tos = self:u8(self.ip_offset + 1)
  self.ip_len = self:u16(self.ip_offset + 2)
  self.ip_id = self:u16(self.ip_offset + 4)
  self.ip_off = self:u16(self.ip_offset + 6)
  self.ip_rf = (self.ip_off & 0x8000)~=0 -- true/false
  self.ip_df = (self.ip_off & 0x4000)~=0
  self.ip_mf = (self.ip_off & 0x2000)~=0
  self.ip_off = (self.ip_off & 0x1FFF) -- fragment offset
  self.ip_ttl = self:u8(self.ip_offset + 8)
  self.ip_p = self:u8(self.ip_offset + 9)
  self.ip_sum = self:u16(self.ip_offset + 10)
  self.ip_bin_src = self:raw(self.ip_offset + 12,4) -- raw 4-bytes string
  self.ip_bin_dst = self:raw(self.ip_offset + 16,4)
  self.ip_src = ipOps.str_to_ip(self.ip_bin_src) -- formatted string
  self.ip_dst = ipOps.str_to_ip(self.ip_bin_dst)
  self.ip_opt_offset = self.ip_offset + 20
  self.ip_options = self:parse_options(self.ip_opt_offset, ((self.ip_hl*4)-20))
  self.ip_data_offset = self.ip_offset + self.ip_hl*4
  return true
end
--- Parse an IPv6 packet header.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:ip6_parse(force_continue)
  self.ip6_offset = 0
  if #self.buf < 40 then -- too short
    return false
  end
  self.ip_v = (self:u8(self.ip6_offset + 0) & 0xF0) >> 4
  if self.ip_v ~= 6 then -- not ipv6
    return false
  end
  self.ip6 = true
  self.ip6_tc = (self:u16(self.ip6_offset + 0) & 0x0FF0) >> 4
  self.ip6_fl = (self:u8(self.ip6_offset + 1) & 0x0F)*65536 + self:u16(self.ip6_offset + 2)
  self.ip6_plen = self:u16(self.ip6_offset + 4)
  self.ip6_nhdr = self:u8(self.ip6_offset + 6)
  self.ip6_hlimt = self:u8(self.ip6_offset + 7)
  self.ip_bin_src = self:raw(self.ip6_offset + 8, 16)
  self.ip_bin_dst = self:raw(self.ip6_offset + 24, 16)
  self.ip_src = ipOps.str_to_ip(self.ip_bin_src)
  self.ip_dst = ipOps.str_to_ip(self.ip_bin_dst)
  self.ip6_data_offset = 40
  return true
end
--- Pare an IPv6 extension header. Just jump over it at the moment.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:ipv6_ext_header_parse(force_continue)
  local ext_hdr_len = self:u8(self.ip6_data_offset + 1)
  ext_hdr_len = ext_hdr_len*8 + 8
  self.ip6_data_offset = self.ip6_data_offset + ext_hdr_len
  self.ip6_nhdr = self:u8(self.ip6_data_offset)
end
--- Set the payload length field.
-- @param plen Payload length.
function Packet:ip6_set_plen(plen)
  self:set_u16(self.ip6_offset + 4, plen)
  self.ip6_plen = plen
end
--- Set the header length field.
function Packet:ip_set_hl(len)
  self:set_u8(self.ip_offset + 0, (self.ip_v << 4) | (len & 0x0F))
  self.ip_v = (self:u8(self.ip_offset + 0) & 0xF0) >> 4
  self.ip_hl = (self:u8(self.ip_offset + 0) & 0x0F) -- header_length or data_offset
end
--- Set the packet length field.
-- @param len Packet length.
function Packet:ip_set_len(len)
  self:set_u16(self.ip_offset + 2, len)
  self.ip_len = len
end
--- Set the packet identification field.
-- @param id packet ID.
function Packet:ip_set_id(id)
  self:set_u16(self.ip_offset + 4, id)
  self.ip_id = id
end
--- Set the TTL.
-- @param ttl TTL.
function Packet:ip_set_ttl(ttl)
  self:set_u8(self.ip_offset + 8, ttl)
  self.ip_ttl = ttl
end
--- Set the checksum.
-- @param checksum Checksum.
function Packet:ip_set_checksum(checksum)
  self:set_u16(self.ip_offset + 10, checksum)
  self.ip_sum = checksum
end
--- Count checksum for packet and save it.
function Packet:ip_count_checksum()
  self:ip_set_checksum(0)
  local csum = in_cksum( self.buf:sub(0, self.ip_offset + self.ip_hl*4)  )
  self:ip_set_checksum(csum)
end
--- Set the source IP address.
-- @param binip The source IP address as a byte string.
function Packet:ip_set_bin_src(binip)
  local nrip = u32(binip, 0)
  self:set_u32(self.ip_offset + 12, nrip)
  self.ip_bin_src = self:raw(self.ip_offset + 12,4) -- raw 4-bytes string
end
--- Set the destination IP address.
-- @param binip The destination IP address as a byte string.
function Packet:ip_set_bin_dst(binip)
  local nrip = u32(binip, 0)
  self:set_u32(self.ip_offset + 16, nrip)
  self.ip_bin_dst = self:raw(self.ip_offset + 16,4)
end
--- Set the IP options field (and move the data, count new length,
-- etc.).
-- @param ipoptions IP options.
function Packet:ip_set_options(ipoptions)
  -- packet = <ip header> + ipoptions + <payload>
  local buf = self.buf:sub(0+1,self.ip_offset + 20) .. ipoptions .. self.buf:sub(self.ip_data_offset+1)
  self.buf = buf
  -- set ip_len
  self:ip_set_len(self.buf:len())
  -- set ip_hl
  self:ip_set_hl(5 + ipoptions:len()/4)
  -- set data offset correctly
  self.ip_options = self:parse_options(self.ip_opt_offset, ((self.ip_hl*4)-20))
  self.ip_data_offset = self.ip_offset + self.ip_hl*4
  if self.tcp then
    self.tcp_offset = self.ip_data_offset
  elseif self.icmp then
    self.icmp_offset = self.ip_data_offset
  end
end

--- Get a short string representation of the IP header.
-- @return A string representation of the IP header.
function Packet:ip_tostring()
  return string.format(
  "IP %s -> %s",
  self.ip_src,
  self.ip_dst)
end

--- Parse IP/TCP options into a table.
-- @param offset Offset at which options start.
-- @param length Length of options.
-- @return Table of options.
function Packet:parse_options(offset, length)
  local options = {}
  local op = 1
  local opt_ptr = 0
  while opt_ptr < length do
    local t, l, d
    options[op] = {}

    t = self:u8(offset + opt_ptr)
    options[op].type = t
    if t==0 or t==1 then
      l = 1
      d = nil
    else
      l = self:u8(offset + opt_ptr + 1)
      if l > 2 then
        d = self:raw(offset + opt_ptr + 2, l-2)
      end
    end
    options[op].len  = l
    options[op].data = d
    opt_ptr = opt_ptr + l
    op = op + 1
  end
  return options
end

--- Get a short string representation of the packet.
-- @return A string representation of the packet.
function Packet:tostring()
  if self.tcp then
    return self:tcp_tostring()
  elseif self.udp then
    return self:udp_tostring()
  elseif self.icmp then
    return self:icmp_tostring()
  elseif self.ip then
    return self:ip_tostring()
  end
  return "<no tostring!>"
end

----------------------------------------------------------------------------------------------------------------
--- Parse an ICMP packet header.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:icmp_parse(force_continue)
  self.icmp_offset = self.ip_data_offset
  if #self.buf < self.icmp_offset + 8 then -- let's say 8 bytes minimum
    return false
  end
  self.icmp = true
  self.icmp_type = self:u8(self.icmp_offset + 0)
  self.icmp_code = self:u8(self.icmp_offset + 1)
  self.icmp_sum = self:u16(self.icmp_offset + 2)

  if self.icmp_type == 3 or self.icmp_type == 4 or self.icmp_type == 11 or self.icmp_type == 12 then
    self.icmp_payload = true
    self.icmp_r0 = self:u32(self.icmp_offset + 4)
    self.icmp_payload_offset = self.icmp_offset + 8
    if #self.buf < self.icmp_payload_offset + 24 then
      return false
    end
    self.icmp_payload = Packet:new(self.buf:sub(self.icmp_payload_offset+1), self.packet_len - self.icmp_payload_offset, true)
  end
  return true
end
--- Get a short string representation of the ICMP header.
-- @return A string representation of the ICMP header.
function Packet:icmp_tostring()
  return self:ip_tostring() .. " ICMP(" .. self.icmp_payload:tostring() .. ")"
end

----------------------------------------------------------------------------------------------------------------
--- Parse an ICMPv6 packet header.
-- @param force_continue Ignored.
-- @return Whether the parsing succeeded.
function Packet:icmpv6_parse(force_continue)
  self.icmpv6_offset = self.ip6_data_offset
  if #self.buf < self.icmpv6_offset + 8 then -- let's say 8 bytes minimum
    return false
  end
  self.icmpv6 = true
  self.icmpv6_type = self:u8(self.icmpv6_offset + 0)
  self.icmpv6_code = self:u8(self.icmpv6_offset + 1)

  if self.icmpv6_type == ND_NEIGHBOR_SOLICIT then
    self.ns_target = self:raw(self.icmpv6_offset + 8, 16)
  end
  return true
end

----------------------------------------------------------------------------------------------------------------
-- Parse a TCP packet header.
-- @param force_continue Whether a short packet causes parsing to fail.
-- @return Whether the parsing succeeded.
function Packet:tcp_parse(force_continue)
  self.tcp = true
  self.tcp_offset = self.ip_data_offset or self.ip6_data_offset
  if #self.buf < self.tcp_offset + 4 then
    return false
  end
  self.tcp_sport = self:u16(self.tcp_offset + 0)
  self.tcp_dport = self:u16(self.tcp_offset + 2)
  if #self.buf < self.tcp_offset + 20 then
    if force_continue then
      return true
    else
      return false
    end
  end
  self.tcp_seq = self:u32(self.tcp_offset + 4)
  self.tcp_ack = self:u32(self.tcp_offset + 8)
  self.tcp_hl = (self:u8(self.tcp_offset+12) & 0xF0) >> 4 -- header_length or data_offset
  self.tcp_x2 = (self:u8(self.tcp_offset+12) & 0x0F)
  self.tcp_flags = self:u8(self.tcp_offset + 13)
  self.tcp_th_fin = (self.tcp_flags & 0x01)~=0 -- true/false
  self.tcp_th_syn = (self.tcp_flags & 0x02)~=0
  self.tcp_th_rst = (self.tcp_flags & 0x04)~=0
  self.tcp_th_push = (self.tcp_flags & 0x08)~=0
  self.tcp_th_ack = (self.tcp_flags & 0x10)~=0
  self.tcp_th_urg = (self.tcp_flags & 0x20)~=0
  self.tcp_th_ece = (self.tcp_flags & 0x40)~=0
  self.tcp_th_cwr = (self.tcp_flags & 0x80)~=0
  self.tcp_win = self:u16(self.tcp_offset + 14)
  self.tcp_sum = self:u16(self.tcp_offset + 16)
  self.tcp_urp = self:u16(self.tcp_offset + 18)
  self.tcp_opt_offset = self.tcp_offset + 20
  self.tcp_options = self:parse_options(self.tcp_opt_offset, ((self.tcp_hl*4)-20))
  self.tcp_data_offset = self.tcp_offset + self.tcp_hl*4

  if self.ip_len then
    self.tcp_data_length = self.ip_len - self.tcp_offset - self.tcp_hl*4
  else
    self.tcp_data_length = self.ip6_plen - self.tcp_hl*4
  end
  self:tcp_parse_options()
  return true
end

--- Get a short string representation of the TCP packet.
-- @return A string representation of the TCP header.
function Packet:tcp_tostring()
  return string.format(
  "TCP %s:%i -> %s:%i",
  self.ip_src, self.tcp_sport,
  self.ip_dst, self.tcp_dport
  )
end

--- Parse options for TCP header.
function Packet:tcp_parse_options()
  local eoo = false
  for _,opt in ipairs(self.tcp_options) do
    if eoo then
      self.tcp_opt_after_eol = true
    end

    if opt.type == 0 then -- end of options
      eoo = true
    elseif opt.type == 2 then    -- MSS
      self.tcp_opt_mss = u16(opt.data, 0)
      self.tcp_opt_mtu = self.tcp_opt_mss + 40
    elseif opt.type == 3 then     -- widow scaling
      self.tcp_opt_ws  = u8(opt.data, 0)
    elseif opt.type == 8 then     -- timestamp
      self.tcp_opt_t1 = u32(opt.data, 0)
      self.tcp_opt_t2 = u32(opt.data, 4)
    end
  end
end

--- Set the TCP source port.
-- @param port Source port.
function Packet:tcp_set_sport(port)
  self:set_u16(self.tcp_offset + 0, port)
  self.tcp_sport = port
end
--- Set the TCP destination port.
-- @param port Destination port.
function Packet:tcp_set_dport(port)
  self:set_u16(self.tcp_offset + 2, port)
  self.tcp_dport = port
end
--- Set the TCP sequence field.
-- @param new_seq Sequence.
function Packet:tcp_set_seq(new_seq)
  self:set_u32(self.tcp_offset + 4, new_seq)
  self.tcp_seq = new_seq
end
--- Set the TCP flags field (like SYN, ACK, RST).
-- @param new_flags Flags, represented as an 8-bit number.
function Packet:tcp_set_flags(new_flags)
  self:set_u8(self.tcp_offset + 13, new_flags)
  self.tcp_flags = new_flags
end
--- Set the urgent pointer field.
-- @param urg_ptr Urgent pointer.
function Packet:tcp_set_urp(urg_ptr)
  self:set_u16(self.tcp_offset + 18, urg_ptr)
  self.tcp_urp = urg_ptr
end
--- Set the TCP checksum field.
-- @param checksum Checksum.
function Packet:tcp_set_checksum(checksum)
  self:set_u16(self.tcp_offset + 16, checksum)
  self.tcp_sum = checksum
end
--- Count and save the TCP checksum field.
function Packet:tcp_count_checksum()
  self:tcp_set_checksum(0)
  local proto = self.ip_p
  local length = self.buf:len() - self.tcp_offset
  local b = self.ip_bin_src ..
    self.ip_bin_dst ..
    "\0" ..
    string.char(proto) ..
    set_u16("..", 0, length) ..
    self.buf:sub(self.tcp_offset+1)

  self:tcp_set_checksum(in_cksum(b))
end

--- Map an MTU to a link type string. Stolen from p0f.
-- @return A string describing the link type.
function Packet:tcp_lookup_link()
  local mtu_def = {
    {["mtu"]=256,   ["txt"]= "radio modem"},
    {["mtu"]=386,   ["txt"]= "ethernut"},
    {["mtu"]=552,   ["txt"]= "SLIP line / encap ppp"},
    {["mtu"]=576,   ["txt"]= "sometimes modem"},
    {["mtu"]=1280,  ["txt"]= "gif tunnel"},
    {["mtu"]=1300,  ["txt"]= "PIX, SMC, sometimes wireless"},
    {["mtu"]=1362,  ["txt"]= "sometimes DSL (1)"},
    {["mtu"]=1372,  ["txt"]= "cable modem"},
    {["mtu"]=1400,  ["txt"]= "(Google/AOL)"},
    {["mtu"]=1415,  ["txt"]= "sometimes wireless"},
    {["mtu"]=1420,  ["txt"]= "GPRS, T1, FreeS/WAN"},
    {["mtu"]=1423,  ["txt"]= "sometimes cable"},
    {["mtu"]=1440,  ["txt"]= "sometimes DSL (2)"},
    {["mtu"]=1442,  ["txt"]= "IPIP tunnel"},
    {["mtu"]=1450,  ["txt"]= "vtun"},
    {["mtu"]=1452,  ["txt"]= "sometimes DSL (3)"},
    {["mtu"]=1454,  ["txt"]= "sometimes DSL (4)"},
    {["mtu"]=1456,  ["txt"]= "ISDN ppp"},
    {["mtu"]=1458,  ["txt"]= "BT DSL (?)"},
    {["mtu"]=1462,  ["txt"]= "sometimes DSL (5)"},
    {["mtu"]=1470,  ["txt"]= "(Google 2)"},
    {["mtu"]=1476,  ["txt"]= "IPSec/GRE"},
    {["mtu"]=1480,  ["txt"]= "IPv6/IPIP"},
    {["mtu"]=1492,  ["txt"]= "pppoe (DSL)"},
    {["mtu"]=1496,  ["txt"]= "vLAN"},
    {["mtu"]=1500,  ["txt"]= "ethernet/modem"},
    {["mtu"]=1656,  ["txt"]= "Ericsson HIS"},
    {["mtu"]=2024,  ["txt"]= "wireless/IrDA"},
    {["mtu"]=2048,  ["txt"]= "Cyclom X.25 WAN"},
    {["mtu"]=2250,  ["txt"]= "AiroNet wireless"},
    {["mtu"]=3924,  ["txt"]= "loopback"},
    {["mtu"]=4056,  ["txt"]= "token ring (1)"},
    {["mtu"]=4096,  ["txt"]= "Sangoma X.25 WAN"},
    {["mtu"]=4352,  ["txt"]= "FDDI"},
    {["mtu"]=4500,  ["txt"]= "token ring (2)"},
    {["mtu"]=9180,  ["txt"]= "FORE ATM"},
    {["mtu"]=16384, ["txt"]= "sometimes loopback (1)"},
    {["mtu"]=16436, ["txt"]= "sometimes loopback (2)"},
    {["mtu"]=18000, ["txt"]= "token ring x4"},
  }
  if not self.tcp_opt_mss or self.tcp_opt_mss==0 then
    return "unspecified"
  end
  for _,x in ipairs(mtu_def) do
    local mtu = x["mtu"]
    local txt = x["txt"]
    if self.tcp_opt_mtu == mtu then
      return txt
    end
    if self.tcp_opt_mtu < mtu then
      return string.format("unknown-%i", self.tcp_opt_mtu)
    end
  end
  return string.format("unknown-%i", self.tcp_opt_mtu)
end

----------------------------------------------------------------------------------------------------------------
-- Parse a UDP packet header.
-- @param force_continue Whether a short packet causes parsing to fail.
-- @return Whether the parsing succeeded.
function Packet:udp_parse(force_continue)
  self.udp = true
  self.udp_offset = self.ip_data_offset or self.ip6_data_offset
  if #self.buf < self.udp_offset + 4 then
    return false
  end
  self.udp_sport = self:u16(self.udp_offset + 0)
  self.udp_dport = self:u16(self.udp_offset + 2)
  if #self.buf < self.udp_offset + 8 then
    if force_continue then
      return true
    else
      return false
    end
  end
  self.udp_len = self:u16(self.udp_offset + 4)
  self.udp_sum = self:u16(self.udp_offset + 6)

  return true
end

--- Get a short string representation of the UDP packet.
-- @return A string representation of the UDP header.
function Packet:udp_tostring()
  return string.format(
  "UDP %s:%i -> %s:%i",
  self.ip_src, self.udp_sport,
  self.ip_dst, self.udp_dport
  )
end

---
-- Set the UDP source port.
-- @param port Source port.
function Packet:udp_set_sport(port)
  self:set_u16(self.udp_offset + 0, port)
  self.udp_sport = port
end
---
-- Set the UDP destination port.
-- @param port Destination port.
function Packet:udp_set_dport(port)
  self:set_u16(self.udp_offset + 2, port)
  self.udp_dport = port
end
---
-- Set the UDP payload length.
-- @param len UDP payload length.
function Packet:udp_set_length(len)
  self:set_u16(self.udp_offset + 4, len)
  self.udp_len = len
end
---
-- Set the UDP checksum field.
-- @param checksum Checksum.
function Packet:udp_set_checksum(checksum)
  self:set_u16(self.udp_offset + 6, checksum)
  self.udp_sum = checksum
end
---
-- Count and save the UDP checksum field.
function Packet:udp_count_checksum()
  self:udp_set_checksum(0)
  local proto = self.ip_p
  local length = self.buf:len() - self.udp_offset
  local b = self.ip_bin_src ..
    self.ip_bin_dst ..
    "\0" ..
    string.char(proto) ..
    set_u16("..", 0, length) ..
    self.buf:sub(self.udp_offset+1)

  self:udp_set_checksum(in_cksum(b))
end


return _ENV;

Youez - 2016 - github.com/yon3zu
LinuXploit