東大校園網很不好用,我在宿舍連着網。當我出去自習的時候,也想用網,就連不上。
因為東大校園網只允許一個人使用,這使得想合伙共用一個賬號的人就沒法整了。學校這么做多半是為了多掙點錢,這對於一個月只用2,3G的人是一種剝削。既然制度不對,為什么不改呢?
於是只能先斷開一下,在重新登陸校園網了。可是坑爹的問題又出現了,有三個按鈕:連接,斷開連接,斷開全部連接。
我點了“斷開網絡”,然后再“連接網絡”,它還告訴我:當前連接數大於一。
實際上,只有一個管用:應該點“斷開全部連接”,再點“連接網絡”。
那么就得分析一下為啥會有這種逗比的情況:編這個頁面的人多半是同情貧苦大眾的,他以為學校肯定會開明到允許多個學生共用一個賬號(然而他高估了學校),這樣一來,中間那個按鈕就起作用了,那個按鈕就是為多個用戶共用一個賬號而生的。但是最終那個按鈕沒能派上用場,反倒成了累贅,總是誤導人,不信可以統計一下,有多少人在一分鍾之內先點了“斷開連接”,然后又點了“斷開全部連接”,這就說明又多少次點中間按鈕是不管用的,是不符合人類需求的。學校既然狠心一人一個賬號來剝削群眾,為啥就不刪除哪一個按鈕呢?
連上了網,一下子還開了一個小窗口,為啥不把這個窗口所顯示的信息跟頁面合並呢。這就使得我被迫多移動一次鼠標去關它。
實際上,這個功能是后來添加的。http://jifei.neu.edu.cn/stats/dashboard?sid=12815848134566654這個鏈接里面的參數sid是隨機生成的,發送到服務器上,服務器完成查詢之后,將流量信息保存到一個hash表中,鍵是這個隨機數,值是流量使用情況。所以這個是實現是有可能出bug的,就是可能撞車,張三和李四同時登陸校園網,可能張三看到的流量信息是李四的。
如果用linux登陸校園網,可以用下面這個腳本,把用戶名和密碼改一下就可以了。#!/bin/bash
#use 'ping' to check whether you are connected to NEU
ping -c2 'www.neu.edu.cn' || { echo "You should connect to NEU firstly" ;exit 0 ; }
user='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
password='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
temp=`mktemp`
#disconnect all the connections
curl -d "uid=$user&password=$password&range=2&timeout=1&operation=disconnectall" "http://ipgw.neu.edu.cn/ipgw/ipgw.ipgw" -o $temp
iconv -f "gb2312" -t "utf-8" $temp -o $temp
cat $temp | grep '<td>.*</td>'
#if ask connect,connect it
if test $# -eq 0;then
curl -d "uid=$user&password=$password&range=2&timeout=1&operation=connect" "http://ipgw.neu.edu.cn/ipgw/ipgw.ipgw" -o $temp
iconv -f "gb2312" -t "utf-8" $temp -o $temp
cat $temp | grep '<td>.*</td>'
fi
#output how much energy did you use .
curl -d "uid=$user&password=$password" "http://jifei.neu.edu.cn/stats/dashboard?sid=0" -o $temp
curl "http://jifei.neu.edu.cn/stats/dashboard?sid=0" -o $temp
res=`cat $temp | grep '<li>.*MB</li>'`
res=${res//[<li>,<\/li>]/}
echo "$res"
還可以用一個網頁打開,原理是用js向服務器post表單,自動登陸。
<html>
<script>
var name='stu_20124003';
var password="xxxxxxxxxxxxxxxxxxxxxxxxxxx";
var user="uid="+name+"&password="+password;
var data=user+"&range=2&timeout=1&";
var x="http://ipgw.neu.edu.cn/ipgw/ipgw.ipgw";
var y= "http://jifei.neu.edu.cn/stats/dashboard?sid=0";
function post(url,data){
var q=new XMLHttpRequest();
q.open("post",url);
q.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
q.send(data);
}
post(x,encodeURI(data+"operation=disconnectall"));
post(x,encodeURI(data+"operation=connect"));
post(y,encodeURI(user));
location=y;
</script>
</ht
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;
public class URLConnectionPost {
static void post(String url, String data) {
try {
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("content-type", "application/x-www-form-urlencoded");
OutputStream cout = connection.getOutputStream();
cout.write(data.getBytes());
cout.close();
connection.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String name = "stu_20124003", password = "xxxxxxxxxxxxx";
String user = "uid=" + name + "&password=" + password, data = user + "&range=2&timeout=1&";
String x = "http://ipgw.neu.edu.cn/ipgw/ipgw.ipgw", y = "http://jifei.neu.edu.cn/stats/dashboard?sid=0";
post(x, data + "operation=disconnectall");
post(x, data + "operation=connect");
post(y, user);
try {
Scanner cin = new Scanner(new URL(y).openConnection().getInputStream());
while(cin.hasNext()){
System.out.println(cin.nextLine());
}
cin.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在連接校園網之前程序會點擊“斷開全部連接”,然后再點擊“連接”。所以只要連着校園網,一旦打開這個網頁就肯定登陸了。
public class Main { static String tos(InputStream cin) { Scanner in = new Scanner(cin); String ans = ""; while (in.hasNext()) { ans += in.nextLine() + "\n"; } in.close(); return ans; } static InputStream post(String url, String data) { try { URLConnection connection = new URL(url).openConnection(); connection.setDoOutput(true); connection.setRequestProperty("content-type", "application/x-www-form-urlencoded"); OutputStream cout = connection.getOutputStream(); cout.write(data.getBytes()); cout.close(); return connection.getInputStream(); } catch (Exception e) { System.out.println("沒連校園網"); // e.printStackTrace();
} return null; } public static void main(String[] args) { String name = "stu_20124003", password = "xxxxxxxxx"; String user = "username=" + name + "&password=" + password; String base = "http://ipgw.neu.edu.cn:803/"; String logout = base + "include/auth_action.php"; String login = base + "srun_portal_pc.php?ac_id=1&"; post(logout, user + "&action=logout&ajax=1"); post(login, user + "&action=login&ac_id=1"); InputStream cin = post(logout, "action=get_online_info"); String s[] = tos(cin).split(","); System.out.println("已用流量:"
+ new DecimalFormat("#,###").format(Long.parseLong(s[0]))); long time = Long.parseLong(s[1]); System.out.println("登錄時間:" + String.format("%02d:%02d:%02d", time / 3600, (time / 60) % 60, time % 60)); System.out.println("賬戶余額:" + s[2]); System.out.println("IP地址:" + s[5]); } }
順道學學python
from urllib.request import Request, urlopen def post(url, data, doCallback): req = Request(url) fd = urlopen(req, data.encode(encoding='utf_8')) if(doCallback): return fd.read().decode("utf_8") name = "stu_20124003" password = "xxxxxxxx" user = "username=" + name + "&password=" + password base = "http://ipgw.neu.edu.cn:803/"; logout = base + "include/auth_action.php"; login = base + "srun_portal_pc.php?ac_id=1&"; post(logout, user + "&action=logout&ajax=1", False) post(login, user + "&action=login&ac_id=1", False); ans = post(logout, "action=get_online_info", True) value = ans.split(sep=',') def formatFlux(s): ans = "" danwei = "B,K,M,G".split(",") i=len(danwei)-1
while i>=0: if i*3<=len(s): ans+=s[max(len(s)-i*3-3,0):len(s)-i*3]+danwei[i]+' ' i=i-1
return ans print("已用流量:" + formatFlux(value[0])) t = int(value[1]) print("登錄時間:%02d:%02d:%02d" % (t / 3600, (t / 60) % 60, t % 60)) print ("賬戶余額:" + value[2]) print("IP地址:" + value[5])
javascript也好用,不過是setHeader幾下罷了。
<html>
<h1 id='haha'></h1>
<script>
var name = 'stu_20124003'; var password = "xxxxxxxxx"; var user = "username=" + name + "&password=" + password; function post(url, data, doCallback) { var q = new XMLHttpRequest(); q.open("post", url); q.setRequestHeader('Referer', 'http://ipgw.neu.edu.cn:803'); q.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
q.setRequestHeader("Origin","http://ipgw.neu.edu.cn:804"); if (doCallback) { q.onreadystatechange = function(q) { if (q.readyState == 4 && q.status == 200) { document.getElementById('haha').innerHtml = q.responseText; } }; } q.send(data); } var base = "http://ipgw.neu.edu.cn:803/"; var logout = base + "include/auth_action.php"; var login = base + "srun_portal_pc.php?ac_id=1&"; post(logout, user + "&action=logout&ajax=1", false); post(login, user + "&action=login&ac_id=1", false); post(logout, "action=get_online_info", true); </script>
</html>
林教主發現,斷開連接時還需要post用戶名,無需post正確的密碼,后台沒有對密碼進行檢測是否正確.於是,林教主把全校人的校園網斷開了一遍.
現在我來北航了,北航校園網1G只要5毛錢,允許多人同時在線,節假日免費,每月初贈送1G,登錄頁面還算漂亮.總而言之,北航校園網比東北大學建設的好多了.
public class Main { static boolean post(String url, String data) throws IOException { URLConnection connection = new URL(url).openConnection(); connection.setDoOutput(true); OutputStream cout = connection.getOutputStream(); cout.write(data.getBytes()); cout.close(); StringBuilder builder = new StringBuilder(); Scanner cin = new Scanner(connection.getInputStream()); while (cin.hasNext()) { builder.append(cin.nextLine()); } cin.close(); return builder.toString().contains("login_ok"); } public static void main(String[] args) throws IOException { String username = "xxxxx", password = "xxxxx"; while (false == post( "https://gw.buaa.edu.cn:802/include/auth_action.php", "action=login&username=" + username + "&password={B}" + Base64.getEncoder() .encodeToString(password.getBytes()) + "&save_me=1&ajax=1&ac_id=4")); } }
用python的requests庫實現起來更簡單
import requests import base64 username = "xxxx" password = "xxxx" def go(action="login"): resp = requests.post("https://gw.buaa.edu.cn:802/include/auth_action.php", data={ "action": action, "username": username, "password": "{B}" + base64.encodebytes(password.encode("utf8")).decode("utf8"), "save_me": 0, "ajax": 1, "ac_id": 22, }) resp.encoding = "utf8" print(resp.text) go("login")
手機端登錄時,需要打開瀏覽器輸入用戶名密碼,十分麻煩,所以編了一個android app,方便一鍵登錄.本程序能自動打開wifi,鏈接校園網,然后點一下登錄並退出就可以了.把用戶名和密碼存儲在SharedPreference里面,因為android經驗很少,特此記錄.
Main.java:本程序唯一的Activity
public class Main extends Activity implements View.OnClickListener { Button loginButton, exitButton; EditText username, password; TextView info; Handler handler = new Handler(); SharedPreferences sharedPreferences; Semaphore semaphore = new Semaphore(1); Runnable runnable = new Runnable() { long lastLoginTime = 0; @Override public void run() { try { semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } if (System.currentTimeMillis() - lastLoginTime < 3000) { return; } else { lastLoginTime = System.currentTimeMillis(); login(username.getText().toString(), password.getText().toString()); } semaphore.release(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); loginButton = (Button) findViewById(R.id.login); exitButton = (Button) findViewById(R.id.exit); username = (EditText) findViewById(R.id.username); password = (EditText) findViewById(R.id.password); info = (TextView) findViewById(R.id.info); loginButton.setOnClickListener(this); exitButton.setOnClickListener(this); init(); username.setText(sharedPreferences.getString("username", "")); password.setText(sharedPreferences.getString("password", "")); } void init() { WifiManager wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE); wifiManager.setWifiEnabled(true); WifiConfiguration config = new WifiConfiguration(); config.SSID = "\"BUAA-WiFi\""; int netId = wifiManager.addNetwork(config); wifiManager.enableNetwork(netId, true); sharedPreferences = this.getSharedPreferences("wifi", 0); } @Override public void onClick(View v) { if (v == exitButton) { finish(); System.exit(0); } if (username.getText().length() == 0 || password.getText().length() == 0) { Toast.makeText(this, "please input username&password", Toast.LENGTH_LONG).show(); return; } if (semaphore.availablePermits() == 1) { new Thread(runnable).start(); } } boolean post(String url, String data) throws IOException { URLConnection connection = new URL(url).openConnection(); connection.setDoOutput(true); OutputStream cout = connection.getOutputStream(); cout.write(data.getBytes()); cout.close(); StringBuilder builder = new StringBuilder(); Scanner cin = new Scanner(connection.getInputStream()); while (cin.hasNext()) { builder.append(cin.nextLine()); } cin.close(); return builder.toString().contains("login_ok"); } void login(String username, String password) { try { int cnt = 2; while (cnt-- > 0 && !post( "https://gw.buaa.edu.cn:802/include/auth_action.php", "action=login&username=" + username + "&password={B}" + Base64.encodeToString(password.getBytes(), Base64.DEFAULT) + "&save_me=1&ajax=1&ac_id=4")) Thread.sleep(1000); if (cnt > 0) { sharedPreferences.edit().putString("username", Main.this.username.getText().toString()).putString("password", Main.this.password.getText().toString()).commit(); exitButton.callOnClick(); } else { handler.post(new Runnable() { @Override public void run() { Toast.makeText(Main.this, "login failed", Toast.LENGTH_LONG).show(); } }); } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
本程序布局文件:唯一的layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <EditText android:id="@+id/username" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="username" /> <EditText android:id="@+id/password" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="password" android:inputType="textPassword" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/exit" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="exit" /> <Button android:id="@+id/login" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="login&exit" /> </LinearLayout> <TextView android:id="@+id/info" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
用網絡請求的方式登錄校園網有時無法成功,這是可以模擬瀏覽器,這樣登錄成功率百分之百,但是運行速度有些慢.下面代碼用到HtmlUnit庫.創建maven項目並添加HtmlUnit的依賴即可.
public class App { public static void main(String[] args) throws Exception { WebClient client = new WebClient(BrowserVersion.CHROME); HtmlPage page = client.getPage( "https://gw.buaa.edu.cn:802/beihanglogin.php?ac_id=22&url=http://gw.buaa.edu.cn:802/beihangview.php"); HtmlTextInput loginname = (HtmlTextInput) page.getElementById("loginname"); HtmlPasswordInput password = (HtmlPasswordInput) page.getElementById("password"); HtmlSubmitInput button = (HtmlSubmitInput) page.getElementById("button"); loginname.setValueAttribute("xxxxx"); password.setValueAttribute("xxxxx"); button.click(); client.close(); } }
帶配置文件的登錄,第一次登錄時會提示輸入用戶名密碼並保存到家目錄下。
import base64 import requests import warnings import time import os import json warnings.filterwarnings("ignore") def login(username, password): print(username,password) resp = requests.post("https://gw.buaa.edu.cn:803/include/auth_action.php", data={ "action": "login", "username": username.lower(), "password": "{B}" + base64.encodebytes(password.encode("utf8")).decode("utf8"), "save_me": 0, "ajax": 1, "ac_id": 22 }, verify=0) resp.encoding = "utf8" if "login_ok" in resp.text: return True else: return False filename = os.path.join(os.path.expanduser("~"), '.school-net.json') if os.path.exists(filename): config = json.load(open(filename,encoding='utf8')) resp = login(config['username'], config['password']) else: while True: username = input("please input username : ").strip() if not username: continue password = input("please input password : ").strip() if not password: continue if login(username, password): break else: print("登錄失敗,可能是用戶名密碼錯誤") config = dict(username=username, password=password) json.dump(config, open(filename,mode="w")) resp = True if resp: print("login ok") else: print("login failed") time.sleep(2)