// ocservFront project main.go | |
package main | |
import ( | |
"bufio" | |
"bytes" | |
"crypto/tls" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"log" | |
"net" | |
"net/http" | |
"os" | |
"regexp" | |
"strings" | |
) | |
const authFormOld = `<?xml version="1.0" encoding="UTF-8"?> | |
<config-auth client="vpn" type="auth-request"> | |
<version who="sg">0.1(1)</version> | |
<auth id="main"> | |
<message>Please enter your username</message> | |
<form method="post" action="/auth"> | |
<input type="text" name="username" label="Username:" /> | |
</form></auth> | |
</config-auth>` | |
const authFormNew = `<?xml version="1.0" encoding="UTF-8"?> | |
<config-auth client="vpn" type="auth-request"> | |
<version who="sg">0.1(1)</version> | |
<auth id="main"> | |
<message>Please enter your username</message> | |
<form method="post" action="/auth"> | |
<input type="text" name="username" label="Username:" /> | |
<input type="password" name="password" label="Password:" /> | |
</form></auth> | |
</config-auth>` | |
var authUserPassRE = regexp.MustCompile("<auth><username>(.*?)</username><password>(.*?)</password></auth>") | |
var vpnCookieRE = regexp.MustCompile("webvpncontext=(.*?);") | |
func main() { | |
//@todo load config from file | |
cert, _ := tls.LoadX509KeyPair("/Users/horsley/Backup/ssl/ihorsley.com.crt", "/Users/horsley/Backup/ssl/ihorsley.com.key") | |
var cfg tls.Config | |
cfg.Certificates = []tls.Certificate{cert} | |
l, err := tls.Listen("tcp", ":15443", &cfg) //@todo load config from file | |
if err != nil { | |
log.Println("listen error:", err) | |
os.Exit(1) | |
} | |
defer l.Close() | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
log.Println("accept error:", err) | |
continue | |
} | |
go func(clientConn net.Conn) { | |
log.Println("conn process start") | |
defer clientConn.Close() | |
//@todo load config from file | |
remoteConn, err := tls.Dial("tcp", "vps9.ihorsley.com:443", nil) //remote can be unix cleartext socket of ocserv | |
if err != nil { | |
log.Println("connect upstream error:", err) | |
return | |
} | |
defer remoteConn.Close() | |
vpnCookie := make(chan string, 1) | |
go func() { //remote => client | |
hackRemoteResponse(clientConn, remoteConn, vpnCookie) | |
io.Copy(clientConn, remoteConn) | |
}() | |
//client => remote | |
hackClientRequest(clientConn, remoteConn, vpnCookie) | |
io.Copy(remoteConn, clientConn) | |
log.Println("conn process done") | |
}(conn) | |
} | |
} | |
//hackClientRequest | |
//hack auth by resend both user and pass form and cookie | |
func hackClientRequest(clientConn, remoteConn net.Conn, vpnCookie chan string) { | |
reader := bufio.NewReader(clientConn) | |
for { //client req hacking | |
req, err := http.ReadRequest(reader) | |
if err != nil { | |
log.Println("ReadRequest from client conn err:", err) | |
return | |
} | |
if req.URL.Path == "/auth" { | |
var buf bytes.Buffer | |
_, err = buf.ReadFrom(req.Body) | |
req.Body.Close() | |
if err != nil { | |
log.Println("read request body from client conn err:", err) | |
return | |
} | |
req.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes())) | |
log.Println("3. second req, auth req, do first sending") | |
req.Write(remoteConn) | |
//waiting for cookie | |
ck := <-vpnCookie | |
log.Println("5. got cookie, resend auth req with cookie") | |
req.Header.Set("Cookie", fmt.Sprintf("webvpncontext=%s;", ck)) | |
req.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes())) | |
req.Write(remoteConn) | |
log.Println("6. resend done, hack finish, going to do regular io.Copy") | |
break | |
} else { | |
log.Println("1. first req, pass") | |
req.Write(remoteConn) | |
} | |
} | |
} | |
//hackRemoteResponse | |
//hack auth by change auth form and drop the first cookie resp | |
func hackRemoteResponse(clientConn, remoteConn net.Conn, vpnCookie chan string) { | |
reader := bufio.NewReader(remoteConn) | |
for { //remote resp hacking | |
resp, err := http.ReadResponse(reader, nil) | |
if err != nil { | |
log.Println("ReadResponse from remote conn err:", err) | |
return | |
} | |
if resp.ContentLength == len(authFormOld) { //hack auth form | |
log.Println("2. first resp, hack resp auth form") | |
resp.Body.Close() | |
resp.ContentLength = int64(len(authFormNew)) | |
resp.Body = ioutil.NopCloser(strings.NewReader(authFormNew)) | |
} else if ck := resp.Header.Get("Set-Cookie"); ck != "" && vpnCookieRE.MatchString(ck) { //get context cookie | |
log.Println("4. second resp, grep cookie, resp hacking finish") | |
if m := vpnCookieRE.FindStringSubmatch(ck); m != nil && m[1] != "" { | |
vpnCookie <- m[1] | |
//log.Println("get vpn cookie:", m[1]) | |
break | |
} | |
} | |
err = resp.Write(clientConn) | |
if err != nil { | |
log.Println("write to client conn err:", err) | |
return | |
} | |
} | |
} |
1
Leafove 2015-05-31 13:57:58 +08:00
要不用输入密码直接换成证书验证就可以了
|
2
horsley OP @Leafove 手机加客户端证书好像又要设置锁屏密码什么的,而且网上教程都是自签的做法,我用的是正规证书不知道怎么弄
|
3
rwzsycwan 2015-05-31 16:05:12 +08:00
@horsley 自己签一个证书用来验证
server-cert 与server-key 填正规证书,底下还有一个ca-cert 填自己签的ca, |
6
bao3 2015-06-03 17:33:08 +08:00
这个hack就不要浪费时间了,直接换成CertAuth方式,不需要radius。另外,android需要强制锁屏密码的问题,其实是你倒入证书的姿势不对或者apk不对。客户端倒入p12证书,android系统不会要求你设置PIN或者密码的。
|