http://[email protected]+13603801618[PST,GMT-8]
WiFiCaptivePortalBot(portal-bot)
Goal:Executeabatteryofofcaptiveportalloginsfromvirtualwifistationsusingthenewerscript.
PublicaccessopenWiFiserviceisoftengatedwithawebsign-onform(acaptiveportal).LANforgevirtualstationscanemulatesign-intothecaptiveportalusingtheportal-bot.plscript.Thisscriptisbynecessityincompletebecausemanycaptiveportalshavedifferentbehaviorsandloginformrequirements.Withthisscript,youprovideabotpluginthatbridgesthegap.Thiscookbookwillcoachyouthroughabasicportal-botintegrationandthenyouwillcreatetenstationsthatauthenticatethroughacaptiveWiFiportal.
Inthisexample,wewillbetestingagainsasimpleLAMPserverontheupstreamsideoftheAP.DonouseyourLANforgeserverastheLAMPserverbecausetheroutingwillbedifficult.Inthischapter,aLAMPserverisat10.26.1.254,andthereisan/etc/hostsentryforbasic-portaltothataddress.
BasicInteractionsofaCaptivePortalThebasicorderofoperationsofacaptiveportalaresummarizedinthesesteps:1. AWiFistationaccessestheLANandisassignedaDHCPaddress.
2. TheAPredirectsanyDNSandHTTP(s)requestfromthestation.Itreturnseitheraloginpagedirectly
a301-Redirecttotheloginpage
3. Thestationusersubmitsthisform.Thisformknowswheretosubmititselfto,butitispossiblethattheformdoesnotsubmittothesameaddressorservicethatitcamefrom.
4. Asuccessfulauthenticationprovidesoneoftheseresponses:Theoriginallyrequestedpage,eitherasa301-Redirectorasaproxiedresult.
Aportal-iframeprovidingalogoutorservicemenuandtheoriginalcontentinside.
Aredirectpagethatusesjavascriptormeta-refreshmechanismstotellthebrowsertoreloadtheoriginallyrequestedpage.
NetworkTestingandEmulationSolutions
ConfiguringaDemoCaptivePortalProvideLogin/Logoutpages
IfyouwishtosetupaloginandlogoutpageonanApache/PHPservertotestwith,youcancopythebelowfilestothe/var/www/htmldirectoryontheLAMPserver.login.php:<!DOCTYPEhtml!><?php$valid=true;if($_SERVER['REQUEST_METHOD']=='POST'){/*customerrorreporting,seeget_explanation*/if(!array_key_exists('username',$_POST)){header("HTTP/1.1400BadRequest");header("X-err-no:9400");header("X-err-msg:missingusername");$valid=false;}}?><html><head><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/><?phpif($valid){?><title>Login</title><?php}else{?><title>BadRequest</title><?php}?></head><body><?phpif($_SERVER['REQUEST_METHOD']=='POST'){?><?phpif(!$valid){?><h1>BadRequest</h1><?phpreturn;}?>
<?=$_POST['username']?>accessgranted.<?php}else{?><formmethod="post"action="">Login:<inputtype="text"name="username"value=""/><br/><inputtype="submit"name="login"value="Login"/></form><?php}?></body></html>
ProvideaRedirectinlieuofPortalCapture
Gettingaredirecttotheloginpagedoesnothavetobeverycomplex.Theportal-botscriptwillfirststartoffrequestingwhateverURLyouwish,sorequesthttp://basic-portal/start.HereisanApacheconfigurationlinetoredirectthatURItologin.php:httpd.conf
<Location/start>Redirect/start/login.php</Location>
Afteraddingthisredirect,restartyourApacherserviceusingthiscommand:
sudoapachectlconfigtest&&sudoapachectlrestart
Testingyourredirect
Youcanusethecommandcurl-sqvhttp://basic-portal/starttotestouttheredirectyoujustcreated.
UsingthePortalBotbashscriptBeforewegetstraighttoworkingwithportal-bot.pl,let'sseehowitisused.YourLANforgeinstallationhasanexamplescriptcalledportal-bot.bash-exampleforyoutocopyandmodify.Thisscriptisintendedforyoutologinandlogoutseparately.TheLANforgemanagerwillcallportal-bot.pldifferentlywhenbuildingupthestationortearingdownthestation,theseactionsaresimilar:
i ./portal-bot.bash willlogyourstationin
i ./portal-bot.bash--logout willlogyourstationout
Insidethebashscript
Theportal-bot.bashscriptisforexercisingyourportal-bot.plscriptoptionsfromthecommandlinewhileyoudevelopwithit.ThisisveryclosetothevaluesyouwillplaceinthePorts→Misc/PostIF-UPfield.
Switchesyouwon'tuseintheGUI
YouwillneverplacethePBOT_NOFORKoptioninthePorts→Misc/PostIF-UPfieldbecausethatwillinterrupttheprocessingoftheLANforgeManagerprocess.Youwillalsoneverplace$*inthatfield,either.Youcanplacethe--verboseand--debugflagsinthere,butitcanfillyourdiskwithlogoutputmorequickly.
Belowisanexampleportal-bot.bashscriptwith \ line-continuationcharactersformattedforclarity:
PBOT_NOFORK=1./portal-bot.pl\--devsta100\--botbp.pm\--ip410.26.2.30\--dns192.168.100.1\--mgt/dev/null\--delays0,1,3\--user"bob"\--pass"secret"\--ap_url"http://basic-portal/"\--start_url"http://basic-portal/start"\--login_form"login.php"\--login_action"login.php"\--logout_url"logout.php"\--verbose--debug$*Belowisthesamescriptusingshortswitches:
PBOT_NOFORK=1./portal-bot.pl\-ista100\-bbp.pm\--ip410.26.2.30\--dns192.168.100.1\--mgt/dev/null\--delays0,1,3\-u"bob"\-p"secret"\-a"http://basic-portal/"\-s"http://basic-portal/start"\-n"login.php"\-o"login.php"\-t"logout.php"\
-v-d$*
Usingtheportal-bot.bashcommandonthecommand-line:
Acommonmisconceptionisthinkingthat$*isacommand-lineargument.Itisonlyusedinbashscripts.Donotput$*onthecommand-line.
PBOT_NOFORK=1./portal-bot.pl-ista100-bbp.pm--ip410.26.2.30\--dns192.168.100.1--mgt/dev/null-u"bob"-p"secret"\-a"http://basic-portal/"-s"http://basic-portal/start"-n"login.php"-o"login.php"-t"logout.php"-v-d
Usingtheportal-bot.plperlscriptTips:
Firstthingtodo:editacopyofthatscriptandadjustitforyourstationdeviceandit'sIPaddress.
Add-dtoaddmoredebuggingmessages.Thatmakesdbg()statementsprint.Add--printafteryougetthescripttowork.ThiswillprintouttheformatoftheargumentsusefulforputtingthestatementsintotheGUIPorts→Misc/PostIF-UPfield.
ThefirstsixargumentsareprovidedbyLANforgewhenyouuseportal-bot.plwithastation.Youwanttopopulatetheseinyourbashscript,butnotinthePostIF_UPfield.
PBOT_NOFORKThisenvironmentvariabletellstheportal-bot.plscripttonotfork.Useitonlywhendeveloping.Omittingthisisnormalandallowsformulti-processingofwebrequestsfromLANforge.
-istationname
--botThebotpluginyouprovide
--ip4TheIPofthestation.ThisscriptisuselessiftherehasbeennoDHCPlease.
--ip6Use''fornoIPv6address.
--dnsTheDNSaddressesprovidedfromtheDHCPlease
--mgtTheFIFOthatsignalstheLANforgeserver.Youdon'tuseitwhentesting.
ThesecondsetofargumentsdescribeyourownAPenvironment:
--user|-uportalusername
--pass|-pportaluserpassword
--ap_url|-aAstringtoprependtoURLswhentalkingtotheAP.Notnecessary,butifyoudon'tuseit,youhavetoprovidefullyqualifiedURLsto--login_form,--login_action,and--logout_form.
--start_url|-sThefirstURLrequestedfromtheAP,thisshouldprovideeitheraloginpageoraredirecttoaloginpage.Ifyougetyourdestinationpage(like,ifyourequestbaidu.comandactuallygetit),yourstationhasprobablynotbeenloggedoutfromthecaptiveportal.
--login_form|-nThisiswhatyourequesttogetaloginform.Oftenitisreturnedintheredirect,butsometimesyoucannotgetacookieassignmentifyoudonotrequestitspecifically.
--login_action|-oSubmityourlogincredentialstothisURL.
--delaysCommaseparatedlistofsecondstodelayatcertainpoints:1. $::delays[0]Usedtodelaytheveryfirst'start_url'GETrequest2. $::delays[1]UsedtodelaythefirstPOSTrequestin'submit_login'3. $::delays[2]Usedtodelaythe'submit_logout'request.4. $::delays[3+]Yourbotcanutilizefurtherdelaysifyouspecify
Youmayspecifyskipsbyaddingazero:--delays1,0,2
Youmayspecifyarandomtimebyusing'random':--delays1,random,2
Youmayspecifyjustonetimeforalldelays:--delays2
Youmayspecifyarandomrange:--delays3-20,4-25
--logout_form|-tSubmittothisURLtologoutofthecaptiveportal
-v-dVerboseanddebugoutput,respectively.
--printSkipsprocessandprintsoutformattedarguments.
$*Expandstoallremainingshellarguments
WewillconnecttoourLANforgesystem*.Youwanttocopythisfiletoyourown./portal-bot.bashfile,edititandthenmakeitexecutable.
i *YoucanconnectviaVNC,PuTTYorotherSSHclient.
i Usechmod+xportal-bot.bash tomakeyourscriptexecutable.
Nowlet'sseehowtousethisscriptwithstationsta100.Runthecommands:
$cd/home/lanforge$chmod+xportal-bot.bash$./portal-bot.bash
Youwillseealotofoutput,itwillshowthecontentsofthewebpagesitfinds.
WatchingtheLogs
Typicallyyouwon'tneedtolookatthisoutputintheterminal,andyouwillnotadd-d-vflagstoyourLANforgestations.Youverylikelywillneedtocheckthelogoutputfromthesescriptsincaseyouneedtodiagnoseconnectionproblemsduringyourtest.Eachvirtualstationleavesaloginthe/home/lanforge/wifidirectory,likewifi/portal-bot.sta100.log
i Watchlogsusingtail:tail-Fwifi/portal-bot.sta100.log
ExecutingtheLANforgecurlcommandsyourself
Tofindtheactualcurlcommandsbeingexecuted,youwanttogrepthelogs.Belowisanexampleofgreppingthelogsandrunningthecurlcommand.
$cd/home/lanforge/wifi$grepSubmittingportal-bot-sta100.logSubmitting:/home/lanforge/local/bin/curl-sLki-c/tmp/sta100_cookie.txt-b/tmp/sta100_cookie.txt-4--interfacesta100--localaddr10.44.4.222--dns-servers192.168.100.1--dns-interfacesta100--dns-ipv4-addr10.44.4.222-XGET'http://basic-portal/start'Submitting:/home/lanforge/local/bin/curl-sLki-c/tmp/sta100_cookie.txt-b/tmp/sta100_cookie.txt-4--interfacesta100--localaddr10.44.4.222--dns-servers192.168.100.1--dns-interfacesta100--dns-ipv4-addr10.44.4.222-XPOST-d'username=bob''http://basic-portal/login.php'
Youmightnoticedthatsomeofthecommandsinthelogmightappearrepeated,thereareareasofredundantlogging.Thereisacasewhereyoucanlegitimatelyseerepeatedcommands:whenyouhaveanPostIF_UPvalue
configuredfortheportyouaretestingwith.(RememberthatthePostIF_UPfieldshouldbeblankwhendevelopingthescript.)
Remember,thiscurlcommandcannotberunwithoutfirstdoingasource/home/lanforge/lanforge.profileinyourshell(ourcurlisacustombuild).Hereisanexample.Wetakeacommandsimilartotheoneabove,add-qvandcancelitusing Ctl-C :
$cd/home/lanforge$sourcelanforge.profile#adda-qvtoseeheaderdetails$/home/lanforge/local/bin/curl-qv-sLki-c/tmp/sta100_cookie.txt-b/tmp/sta100_cookie.txt-4--interfacesta100--localaddr10.41.4.223--dns-interfacesta100--dns-ipv4-addr10.41.4.223http://basic-portal/start*STATE:INIT=>CONNECThandle0xa80158;line1397(connection#-5000)*Addedconnection0.Thecachenowcontains1members*Trying10.51.0.254...*TCP_NODELAYset*bind-local,addr:10.41.4.223dev:sta100*SO_BINDTODEVICEsta100failedwitherrno1:Operationnotpermitted;willdoregularbind*Name'sta100'family2resolvedto'10.41.4.223'family2*Localport:0*STATE:CONNECT=>WAITCONNECThandle0xa80158;line1450(connection#0)^C
ExplainingthecurlCommand
Therearemanyargumentstothecurlcommand,butingeneral,youshouldbeabletocopyandpastethecommandintoaterminalanditshouldwork(seenoteaboutlanforge.profileabove).Belowisanexampleofacurlcommand,with \ charactersasline-continuationmarks,formattedforclarity.
$/home/lanforge/local/bin/curl-qv\-sLki\-c/tmp/sta100_cookie.txt\-b/tmp/sta100_cookie.txt\-4\--interfacesta100\--localaddr10.41.4.223\--dns-interfacesta100\--dns-ipv4-addr10.41.4.223\http://basic-portal/start
Switch ExampleValue Purpose
-q Suppresspageoutput
-v Verbose,printsdiagnosticsteps
-s Suppressespageoutput
-L Followredirects
-k Suppresscertificatevalidationerrors
-i PrintHTTPheaders
-c sta100_cookie.txt Sendcookiesfromfile
-b sta100_cookie.txt Savecookiestofile
-4 UseIPv4
--interface sta100 bindtothisinterface
--localaddr 10.41.4.223 bindtothisaddress
--dns-interface sta100 sendDNSqueriesfromthisinterface
--dns-ipv4-addr 10.41.4.223 bindtothisaddresswhensendingDNSqueries
--dns-interface sta100 sendDNSqueriesfromthisinterface
-XGET UseHTTPGETmethod
POST UseHTTPPOSTmethod-d 'username=bob' URLencodedformparametersusedduringPOSTmethod
Yourportal-bot.bashscriptisintendedtobeawayoffocusingonthedevelopmentofyourbotpluginandnotrepetitivelytypingalongcurlcommand.
WritingyourBotPluginYourbotplugin,thePerlmoduleyouwillwriteforyourcaptiveportal,iscentraltotheoperationoftheportal-bot.plscript.Itisalsoimportantthatyoudonotaltertheportal-bot.plscriptunlessabsolutelynecessary,becauseyourchangescouldbeoverwrittenbyupgrades.Anyalterationtothetimeatwhichthefork()callismadeinthisscriptcanmaketheLANforgeservergrindtoahalt.
i Onlyedityourbotperlmodule,please.
TheBotSubroutines
Theexamplebot,bp.pm,providedwithLANforgedefinesfoursubroutines.Inorder:
find_redirect_urlThissubroutinereceivestheresponseoftheHTTP(S)GETofyour--start_urlparameter.Lookthroughthistoseeif:
youarealreadygettingdestinationcontent--ifso,youwerenotloggedout,
yougetaloginformdirectlyandnotaredirect,
oryougetaredirecttoaloginpage(possiblyonaseparateportlike:8080)
Ifyougetaredirecttoanotherport,comparethe--login_urlvaluetothis.Ifitisdifferent,considerupdatingyourlogin_urlparameter.
Theremightbemanyformparameters,likeonesforasessionid,aPHP_SESSID,acookie,abase64encodedstringindicatingyouroriginallyrequestedurl(orjustaplainURL-encodedurl),andanypossibleco-brandingparametersthatmightindicateanyadvertisingcampaignsassociatedwiththiscaptiveportal.Missingsomeofthesemightmakesubmittingtheformgiveyouanerror.Storethesevaluesasnecessaryinyourbot::namespace.Youdonotsubmityourloginpageinthismethod.
i Defineapackagescopevariableusingour$thing; afteryourpackagestatement.
submit_loginHereiswhereyousubmityourloginpageforms.Thebotlib::request()functionisprovidedtomakeGETandPOSTrequetsverboselogginganddebugging.Thepageisreturnedaslinesinthe@responsearray.
my$post_data="username=".uri_escape($user_name);my@response=();request({'curl_args'=>$::curl_args,'url'=>$post_url,'method'=>'POST','delay'=>'0,3',#see--delaysoption'post_data'=>$post_data,'print'=>1},#turnsondebugging\@response);
Thesubmit_loginfunctionusesthe$::delay[1]parameterif--delayswereset.Seeparagraphon
randomDelay.
interpret_login_responseHereyoudetermineifyouaregettinganaccessdeniederrororarebeingforwardedtoyouroriginalstart_urldestination.Setyour$resultvariabletoOKorFAIL.Usethelogg()methodtoaddinformationforthewifi/portal-botlog.
Inordertoaddevents,suchaspageloadtime,youwanttousethebotlib::newEvent()function:
my$page_time=botlib::time_milli()-$::start_at;newEvent("portal_login:$result",$page_time,$::dev);
Youreventlogwillgainmessageslikethese:
get_explanationSomewebapplicationscanprovidecustomizederrormessagesintheirresponse.Youcanaddaget_explanation()functiontoyourbottocollectthisinformation.Thebotlib::dbgdie()methodwilltakeadvantageofthismethodifavailable.Belowisanexcerptfromthemethodfoundinbp.pm:
subget_explanation{for$line(@$ra_result){($err_code)=$line=~/^X-err-no:(.*)$/if($line=~/^X-err-no:/);($err_msg)=$line=~/^X-err-msg:(.*)$/if($line=~/^X-err-msg:/);}return"$err_code,$err_msg";}
NoticehowthisparsesouttheHTTPheadersfoundiftheparameterusernameweremissingwhendoingaPOSTtobasic-portal/login.php:
header("X-err-no:9400");header("X-err-msg:missingusername");
YouwillseethesemessagesshowupintheLANforgeEventslog:
submit_logoutManycaptiveportalsdonotpublicisetheirlogoutURLs,soitmightbeavailableonlyonanadminpagefortheAP.Youwillknowwhenthelogout_urlparameterworksifyoucandoalogoutwiththatstation,andthensuccessfullylogbackinusingthesamestationandseeingthecaptiveportalsign-inpageagain.
randomDelayThedelayparametertobotlib::request()hasmanyoverloadstothecall:
Asimplenumberisasimpledelayinseconds.Nootherunitsareused.
Ifyouspecify'random'inthedelayparameter,thebotlib::randomDelay()iscalled,producingarangebetween[1-119]seconds.
Ifyouspecify'3-16',randomDelay(3,16)iscalledtoproducearandomrangebetween[3-16]seconds.
Ifyouspecifytwonumbersseparatedbyacomma,itlooksatyour@::delayslist,andpicksthesecondargumentifitcan,thelastitemof@::delaysifthelististooshort,orthefirstargumentiftherearenoitemsinthedelaylist.
Wehavenowcoveredallofthescriptingdevelopmentareasfortheportal-bot.plpluginyouwillwrite.
ConfiguringyourStationsASingleStation
Weassumeyouhaveportal-bot.bashworkingatthispoint.Thisishowyoucanconfigureasinglestation:1. Usetheportal-bot.pl--printcommandtoprintoutthearguments.2. Copytheresult(startingwith"portal-bot.pl")intothePort->Miscwindow.Avoidpopulatingthisfield
whileyouaredevelopingthescript!Ifyouplaceavalueintothatfield,yourportal-botscriptwillnotonlyexecute,buttheManagerprocesswillalsoexecutethescriptspecifiedinthePOST_IFUPfield.Thiscanbereallyconfusing.
MultipleStations
TogetmultiplevirtualstationslogginginanoutusingtheGUI,wejustneedafewofthoseparametersforthestationconfiguration.WewillusetheBatchModifyfeaturetoalteraseriesofstations.1. InthePortstab,createaseriesofstations.Inthisexamplewewillcreatethemwith:
Port:wiphy2
SelectDHCP-IPv4
Quantity:10
STAID:300
SSID:jedtest
Passphrase:jedtest1
SelectWPA2
SelectDown
2. HighlightthemandclickBatchModify.
3. ClicktheDownbutton.
4. Inyourterminal,invoketheportal-bot.bashwiththe--printargument:
./portal-bot.bash--printportal-bot.pl--botbp.pm--userbob--passbob1--ap_urlhttp://basic-portal/--start_urlhttp://basic-portal/start--login_formlogin.php--login_actionlogin.php--logout_formlogout.php
5. Usethe[+]buttontoexpandtoBox2.WewillenterthefollowingversionofourcommandintothePostIF-UPScriptarea.(Thepictureshowstheshortswitches.)
ClickOK
6. InthePortstab,doubleclicksta300andintheMiscConfigurationtab,youwillseethePostIF-UPScriptvalues.
TestingaStation
ExercisingthesestationsstartswithbringingthemupanddownusingtheBatchModifytool.1. Highlightonestation,sta300,andclickBatchModify.2. ClicktheDownbuttontoadmin-downthestation.
3. InashellontheLANforge,gotto/home/lanforge/wifiandtailthelogforstation300:
tail-fportal-bot.sta300.log
4. ClicktheUpbuttontoadmin-upthestation.
5. ClickthePortalLoginbuttonforcethestationtologinifyoudonotseeanymessagesinthelogfileyouaretailing.
TroubleshootingTechniques
Ifyourstationcannottalktothecaptiveportal,likeyouhaveatime-out,thesestepswillhelpidentifywherethereisamisconfiguration:1. PingtheportalfromLANforge:pingbasic-portal
2. Pingtheportalfromsta300:ping-I10.27.0.16basic-portal
3. Usecurltodownloadtheportalpagebyhand:curl-sqvhttp://basic-portal/login.php4. Checktherouteontheportalsideifyouarerouting.Someexamples:
route-n
routeadd-net10.27.0.0/23gw10.26.1.1
5. Checkaccesslogsfortheportal.Theremightbeahostnameissue.
UsingthePortBringupPluginUsingthePortBringupPluginisamuchmorefunwaytogetdatathanlookingatlogfiles.1. InthePluginsmenu,selectPortBringupTest.
3. ClickStart
4. Youwillseethereportingwindow.ItoftentakesmanysecondsorafewminutesforstationstoaquireDHCPaddressesandstartreportinginformationintotheplugin.
CandelaTechnologies,Inc.,2417MainStreet,Suite201,Ferndale,WA98248,USAwww.candelatech.com|[email protected]|+1.360.380.1618