Nav links

Friday, 24 October 2008

Posting a form programmatically

Update 4 Nov 2008: I thought I had it all worked out, but since borrowing a laptop I discovered that I was only part of the way to a solution. The crucial point is that any changes to wireless security will not take effect until a WepEncryption setting has also been changed (either turning it off or on). Thus, the following attempt to switch from WEP to WPA does not work and you end up with an unsecured network. Simply changing the order of the commands fixes this.


port wireless set WepEncryption disabled
port wireless set WPA true


So now everything works!









Update 26 Oct 2008: It turns out that my problem could be solved more simply by just changing the order of my WPA to WEP command to the following (WEP to WPA already works):



port wireless set WPA false
port wireless set WepEncryption 64bit


These telnet commands are pretty undocumented, so it was just luck that I came across this solution.








I recently wrote about how I created a simple Windows program to turn my Billion router's WiFi on and off. Extending this to allow the switching between WEP and WPA2 security turned into a long and unexpected detour, and showed how even a .Net forms program could benefit from Perl.



In theory, switching from WEP to WPA should just be a matter of sending the following commands through the telnet interface:



port wireless set WepEncryption disabled
port wireless set WPA true


After doing this the router reports, via telnet and through its built-in web interface, that WPA is now active. However, my WEP-only Nintendo DS confirms that nothing has physically changed. Even following those commands with further telnet commands to turn the wireless off and then on does not fix it. The only way to make the setting active is to go in via the web interface and click apply. I'm sure there's some telnet command that has a similar effect, but I haven't been able to find it. In the meantime, the way to make my program work is to programmatically press the apply button. Unfortunately, that's easier said than done.



I would like a .Net framework function that, when given a URL, will submit a given form on that page. If you know the content of the form in advance, and you know it won't ever change, then it's just a matter of a signle POST request. In this case, I don't know the content of the form, so I need to retrieve the form, parse it, and send it back. Doing this manually from first principles, especially given the non-standard nature of HTML forms, would be a thankless and never-ending task, so I looked for existing solutions.



Perl has been popular for such a long time amongst coders that it's not surprising that there's a Perl class that does just what I want, HTML::Form.




use LWP 5.64;

my $browser = LWP::UserAgent->new;

#==== config page is password protected
$browser->credentials(
'my.router:80',
'WebAdmin',
'username' => 'password'
);

#==== wireless security page
my $url = 'http://home.gateway/wpa/rt_wpa6.html';

#==== get wireless security page
$response = $browser->get($url);

die "Error: ", $response->header('WWW-Authenticate') ||
'Error accessing',
"\n ", $response->status_line, "\n at $url\n Aborting"
unless $response->is_success;

use HTML::Form;
my @form = HTML::Form->parse($response);

#==== we want to submit the last form on the page
$request = $form[@form-1]->click;

# Pass request to the user agent and get a response back
$response = $browser->request($request);

# Check the outcome of the response
if ($response->is_success) {
print "Succesfully set security";
}
else {
die $response->status_line ;
}


This class easily coped with the router's security, and with the need to submit the last, not the first, form on the given page (the WEP page has two forms, the first empty, and WPA one form, so this copes with either).



Now that I had it working in Perl I attempted to created a version in .Net, to match the rest of the program. Initially it looked like HtmlAgilityPack with the FormProcessor add-on would do the trick, but despite much effort I couldn't get it to work in my situation. The FormProcessor is not quite configurable enough for me. However, the code for both is provided, so with time I should be able to get it to work. However, as I already had a working Perl version the quicker solution was to call that from .Net.



When I first saw the Net framework I marvelled at how complete its library seemed. I now realise that it does have gaps, but these can easily be filled by other languages. From my alliance of Perl and .Net I now have a fully-functional Windows application that provides a pleasant GUI to turn my WIFi on or off, set it to turn off after a set time, and to switch the WiFi security from WEP to WPA and vice-versa.