酒店热点恶作剧

你有没有住过酒店,却总是烦恼需要打开浏览器才能登录无线网络?是的,我也是。最近有一次经历特别令人沮丧,我不得不拿出我最喜欢的瑞士军刀,让我的生活变得轻松一些。

情况概述

背景是这样的,我在山区的一家酒店住了几天。如今幸运的是,酒店提供了无线网络。但奇怪的是,每个房间都有一个独立的用户名和密码。“没问题”,我想,然后迅速打开我的笔记本电脑和Firefox,输入登录信息以获得期待已久的连接。使用Firefox(或其他任何浏览器)是必要的,因为登录页面是通过捕获门户访问的。这就是你看到登录横幅时被引导的地方,就像这样在你的浏览器中弹出

Firefox captive portal login banner

我想这没问题,于是愉快地开始了我的日常生活。

问题来了

第二天开始出现问题。起床并唤醒我的笔记本电脑后,我无法阅读电子邮件2,也无法在irc3上阅读聊天,通过Signal查看消息,或者上网4

而且,ping命令显示的是“目标网络禁止”

$ ping www.heise.de
PING www.heise.de (193.99.144.85) 56(84) bytes of data.
From logout.hotspot.lan (192.168.168.1) icmp_seq=1 Destination Net Prohibited
From logout.hotspot.lan (192.168.168.1) icmp_seq=2 Destination Net Prohibited
From logout.hotspot.lan (192.168.168.1) icmp_seq=3 Destination Net Prohibited
^C
--- www.heise.de ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2002ms

显然,我并没有在线。

这时我再次注意到了Firefox的捕获门户登录横幅(见上图)。哦,我必须再次登录,这很奇怪。点击“打开网络登录页面”按钮后,我自动登录了。无需再次输入登录信息。我也觉得这很奇怪,因为如果登录是自动的,那我为什么还要再次访问登录页面呢?

我让笔记本电脑进入睡眠模式,去村里散步,买些杂货,享受山里的空气5。回来后,我不得不再次登录才能获得无线访问。我开始慢慢变得有点不高兴。我的猜测是,相关终端用户的MAC地址会很快从访问列表中移除,可能在一小时或两小时之内6,因此网络连接会被迅速切断。

一个问题让我的情况变得更糟,那就是我经常同时打开几个浏览器窗口;通常是因为我同时有几个思路,每个窗口都包含与每个思路相关的信息。问题是,只有一个浏览器窗口显示了(自动出现的)捕获门户登录横幅。找到显示横幅的窗口相当费时。

好吧,这开始变得荒谬且有点恼人。是时候自动化这个烦恼了。救星是WWW::Mechanize

WWW::Mechanize as a comic book super hero; generated by DALL-E
WWW::Mechanize作为一个漫画书超级英雄;由DALL-E生成。

解决方案

为什么选择 WWW::Mechanize?好吧,我对它有经验(我在疫情之前曾经用类似的方法自动登录德国的ICE列车以通勤工作),我知道我可以用它来提交简单HTML表单的数据,而且Perl是我的首选自动化脚本语言。

那么,如何开始自动化登录过程呢?简单的解决方案:退出Firefox,关闭所有浏览器窗口,让电脑进入休眠状态,然后出去散步几个小时。

回来后,我只需要使用perl -de0的组合来启动一个类似REPL的环境来尝试,并使用perldoc来阅读丰富的WWW::Mechanize文档

第一次尝试触发连接到 captive portal 的尝试并不顺利

└> perl -de0

Loading DB routines from perl5db.pl version 1.55
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(-e:1):   0
  DB<1> use WWW::Mechanize;

  DB<2> $mech = WWW::Mechanize->new;

  DB<3> $mech->get('https://google.com');

Error GETing https://google.com: Can't connect to google.com:443 (SSL
connect attempt failed) at (eval
22)[/home/cochrane/perl5/perlbrew/perls/perl-5.30.1/lib/5.30.1/perl5db.pl:738]
line 2.

好的,所以我们需要使用 HTTP 而不是 HTTPS。知道这一点很好。

仅使用 HTTP 就好多了

  DB<4> x $mech->get('http://google.com')
0  HTTP::Response=HASH(0x55a95f5048c0)
<snip>
lots of details; you really don't want to see this
</snip>

这正是我们想要的!我们现在至少能收到一些东西。查看页面标题,我们得到

  DB<5> x $mech->title();
0  'myadvise hotspot > login'

是的,这是一个登录页面。使用以下方式转储页面内容

  DB<5> x $mech->content();
<snip>
lots of HTML content
</snip>

我们可以看到我们可以玩的东西。关于内容(我这里不显示,因为细节太多,我想保护无辜者)的主要注意事项是

  • 我们有一个名为 login 的表单

    <form name="login" action="http://login.hotspot.lan/login" method="post">
  • 我们有一个名为 username 的用户名字段

    <input style="width: 80px" name="username" type="text" value=""/>
  • 我们还有一个名为 password 的密码字段

    <input style="width: 80px" name="password" type="password"/>

这为我们提供了足够的信息,可以使用相关的登录数据提交表单。

顺便说一句,这些字段是英文的,尽管网站是德语网站。我想在编程时将字段标准化为英文可能是有用的。

要提交表单,我们使用 WWW::Mechanizesubmit_form() 方法(我已格式化得很好,以便更容易阅读)

$mech->submit_form(
    form_name => 'login',
    fields => {
        username => 'username-for-room',
        password => 'password-for-room',
    }
);

我们可以通过询问 HTTP::Response 来检查表单提交是否成功

  DB<7> x $mech->res->is_success;
0  1

到目前为止看起来不错。让我们看看ping是否按预期工作

$ ping www.heise.de
PING www.heise.de (193.99.144.85) 56(84) bytes of data.
64 bytes from www.heise.de (193.99.144.85): icmp_seq=1 ttl=247 time=20.6 ms
64 bytes from www.heise.de (193.99.144.85): icmp_seq=2 ttl=247 time=13.9 ms
^C
--- www.heise.de ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 13.941/17.281/20.621/3.340 ms

是的!换句话说:我们成功了!这很简单。☺

把所有东西组合起来(并稍微清理一下代码),我最终得到了这个

use strict;
use warnings;

use WWW::Mechanize;

my $mech = WWW::Mechanize->new;
$mech->get('http://google.com');

# check that we have the login page and not Google or something else
# i.e. we're not logged in
if ($mech->title() =~ 'login') {
    $mech->submit_form(
        form_name => 'login',
        fields => {
            username => '<username-for-room>',
            password => '<password-for-room>'
        }
    );
    if ($mech->res->is_success) {
        print "Login successful\n";
    }
    else {
        print "Login failed\n";
    }
}
else {
    print "Already logged in\n";
}

现在,每当我从休眠状态唤醒笔记本电脑,我就能重新上线。太棒了!

从安全角度来看,用户名和密码显然与房间号相关联,这有点奇怪。换句话说,我可能很容易地使用相邻房间的账户(我想:我最终懒得检查)。

结论

好吧,这个脚本确实为我节省了一些时间,避免了从挂起状态唤醒笔记本电脑的麻烦。此外,找出构建解决方案所需的各个部分的乐趣。Perl再次拯救了世界7

最初发布于https://peateasea.de


  1. 还记得找一家有任何无线连接的酒店是多么艰难的任务吗?有点像在机场找到为笔记本电脑充电的电源插座真的很困难,最后不得不坐在清洁员工通常插上吸尘器的房间旁边。啊,那些日子啊 😉。换句话说:人类已经走了很长的一段路。 [return]
  2. 我使用 mutt;它运行得很快,只需使用文本即可发送电子邮件。对吧?对吧? [return]
  3. 我还使用irssi进行IRC。看,我在这里已经有一段时间了,好吗?[返回]
  4. 我属于那些生活在终端的极客之一,因此我倾向于使用很多基于终端的工具来完成事情。[返回]
  5. 我并不是在讽刺:由于森林和远离任何城市,这里的空气要清新得多。你有没有注意到欧洲城市的空气简直糟糕透顶?[返回]
  6. 后来,我尝试让电脑进入休眠状态,然后在几分钟后再唤醒它。连接仍然存在,所以我认为保持连接活跃和注册MAC地址的超时时间大约是几小时,但不超过两三个小时,因为即使在如此短的时间内不活动也必须重新登录。后来的测试显示,超时时间是一个小时。[返回]
  7. 好吧,这实际上救了一周的时间。[返回]

标签

保罗·科克伦

多用途软件开发者和极客

浏览他们的文章

反馈

这篇文章有问题?请在GitHub上打开一个issue或pull request来帮助我们。