编译mipsle版lantern
使用的环境为 腾讯云 Ubuntu Server 16.04.1 LTS 32位
- 安装依赖包
sudo apt-get update
sudo apt-get install git gcc libgtk2.0-dev
sudo apt-get install gcc-mips-linux-gnu g++-mips-linux-gnu gcc-arm-linux-gnueabi g++-arm-linux-gnueabi gcc-mipsel-linux-gnu g++-mipsel-linux-gnu
sudo apt-get install npm nodejs-legacy
sudo apt-get install axel
由于lantern使用的golang是lantern修改过的golang, 所以我们需要将golang官方的版本修改成可以兼容lantern的版本.
wget https://coding.net/u/ilanyu/p/lantern/git/raw/master/lantern_linux_386_server.tar.gz tar -zxvf lantern_linux_386_server.tar.gz ./lantern_linux_386_server -proxyall &> lantern.log & export http_proxy=http://127.0.0.1:8787 export https_proxy=http://127.0.0.1:8787 axel -n 50 https://storage.googleapis.com/golang/go1.8.linux-386.tar.gz sudo tar -C /usr/local -xzf go1.8.linux-386.tar.gz export PATH=$PATH:/usr/local/go/bin axel -n 50 https://storage.googleapis.com/golang/go1.8.src.tar.gz tar -xvf go1.8.src.tar.gz cd ./go/src
修改
~/go/src/net/http/server.go
和~/go/src/net/http/transport.go
server.go中
第291行开始
if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade { return nil, badRequestError("missing required Host header") } if len(hosts) > 1 { return nil, badRequestError("too many Host headers") } if len(hosts) == 1 && !httplex.ValidHostHeader(hosts[0]) { return nil, badRequestError("malformed Host header") } for k, vv := range req.Header { if !httplex.ValidHeaderFieldName(k) { return nil, badRequestError("invalid header name") } for _, v := range vv { if !httplex.ValidHeaderFieldValue(v) { return nil, badRequestError("invalid header value") } } }
修改为
if !c.server.AcceptAnyHostHeader { if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade { return nil, badRequestError("missing required Host header") } if len(hosts) > 1 { return nil, badRequestError("too many Host headers") } if len(hosts) == 1 && !httplex.ValidHostHeader(hosts[0]) { return nil, badRequestError("malformed Host header") } for k, vv := range req.Header { if !httplex.ValidHeaderFieldName(k) { return nil, badRequestError("invalid header name") } for _, v := range vv { if !httplex.ValidHeaderFieldValue(v) { return nil, badRequestError("invalid header value") } } } }
第 2372 行
// standard logger. ErrorLog *log.Logger disableKeepAlives int32 // accessed atomically.
修改为
// standard logger. ErrorLog *log.Logger // AcceptAnyHostHeader, if set to true, forces the server to skip validation // of host headers. AcceptAnyHostHeader bool disableKeepAlives int32 // accessed atomically.
transport.go中
第145行
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle // (keep-alive) connections to keep per-host. If zero, // DefaultMaxIdleConnsPerHost is used. MaxIdleConnsPerHost int // IdleConnTimeout is the maximum amount of time an idle // (keep-alive) connection will remain idle before closing // itself. // Zero means no limit. IdleConnTimeout time.Duration
修改为
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle // (keep-alive) connections to keep per-host. If zero, // DefaultMaxIdleConnsPerHost is used. MaxIdleConnsPerHost int // MaxIdleTime, if non-zero, controls how long to hold on to keep-alive // connections. Once a connection hits its MaxIdleTime, it will be closed. // You need to call EnforceMaxIdleTime() at least once for this to be // enforced on an ongoing basis. MaxIdleTime time.Duration // IdleConnTimeout is the maximum amount of time an idle // (keep-alive) connection will remain idle before closing // itself. // Zero means no limit. IdleConnTimeout time.Duration
第485行
// CloseIdleConnections closes any connections which were previously // connected from previous requests but are now sitting idle in // a "keep-alive" state. It does not interrupt any connections currently // in use. func (t *Transport) CloseIdleConnections() { t.nextProtoOnce.Do(t.onceSetNextProtoDefaults) t.idleMu.Lock() m := t.idleConn t.idleConn = nil t.idleConnCh = nil t.wantIdle = true t.idleLRU = connLRU{} t.idleMu.Unlock() for _, conns := range m { for _, pconn := range conns { pconn.close(errCloseIdleConns) } } if t2 := t.h2transport; t2 != nil { t2.CloseIdleConnections() } } // CancelRequest cancels an in-flight request by closing its connection. // CancelRequest should only be called after RoundTrip has returned. // // Deprecated: Use Request.WithContext to create a request with a // cancelable context instead. CancelRequest cannot cancel HTTP/2 // requests. func (t *Transport) CancelRequest(req *Request) { t.cancelRequest(req, errRequestCanceled) }
修改为
// CloseIdleConnections closes any connections which were previously // connected from previous requests but are now sitting idle in // a "keep-alive" state. It does not interrupt any connections currently // in use. func (t *Transport) CloseIdleConnections() { t.nextProtoOnce.Do(t.onceSetNextProtoDefaults) t.idleMu.Lock() m := t.idleConn t.idleConn = nil t.idleConnCh = nil t.wantIdle = true t.idleLRU = connLRU{} t.idleMu.Unlock() for _, conns := range m { for _, pconn := range conns { pconn.close(errCloseIdleConns) } } if t2 := t.h2transport; t2 != nil { t2.CloseIdleConnections() } } func (t *Transport) EnforceMaxIdleTime() { if t.MaxIdleTime == 0 { // Nothing to maintain return } t.maintainIdleOnce.Do(func() { go func() { for { time.Sleep(t.MaxIdleTime / 10) now := time.Now() toClose := make([]*persistConn, 0) t.idleMu.Lock() for key, conns := range t.idleConn { retainedConns := make([]*persistConn, 0, len(conns)) for _, pconn := range conns { if now.Sub(pconn.lastIdled) > t.MaxIdleTime { toClose = append(toClose, pconn) } else { retainedConns = append(retainedConns, pconn) } } if len(retainedConns) == 0 { delete(t.idleConn, key) } else { t.idleConn[key] = retainedConns } } t.idleMu.Unlock() // Close connections outside of mutex to minimize locking time for _, pconn := range toClose { pconn.close(errCloseIdleConns) } } }() }) } // CancelRequest cancels an in-flight request by closing its connection. // CancelRequest should only be called after RoundTrip has returned. // // Deprecated: Use Request.WithContext to create a request with a // cancelable context instead. CancelRequest cannot cancel HTTP/2 // requests. func (t *Transport) CancelRequest(req *Request) { t.cancelRequest(req, errRequestCanceled) }
第696行
for _, exist := range idles { if exist == pconn { log.Fatalf("dup idle pconn %p in freelist", pconn) } } t.idleConn[key] = append(idles, pconn) t.idleLRU.add(pconn)
修改为
for _, exist := range idles { if exist == pconn { log.Fatalf("dup idle pconn %p in freelist", pconn) } } pconn.lastIdled = time.Now() t.idleConn[key] = append(idles, pconn) t.idleLRU.add(pconn)
第1296行
// mutateHeaderFunc is an optional func to modify extra // headers on each outbound request before it's written. (the // original Request given to RoundTrip is not modified) mutateHeaderFunc func(Header) }
修改为
// mutateHeaderFunc is an optional func to modify extra // headers on each outbound request before it's written. (the // original Request given to RoundTrip is not modified) mutateHeaderFunc func(Header) // when this connection was last idled lastIdled time.Time }
源码修改完成
下面编译修改后的golangGOROOT_BOOTSTRAP=/usr/local/go ./make.bash
将:/usr/local/go/bin从PATH中去除
echo $PATH
得到结果
# /home/ubuntu/bin:/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin
将最后的
/usr/local/go/bin
修改为/home/ubuntu/go/bin
export PATH=/home/ubuntu/bin:/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/ubuntu/go/bin
编译 lantern
unset http_proxy unset https_proxy git clone --depth=1 https://github.com/getlantern/lantern.git cd lantern sudo npm config set registry https://registry.npm.taobao.org sudo npm i gulp-cli -g cp /home/ubuntu/lantern/src/github.com/getlantern/pac/pac_bytes_linux_386.go /home/ubuntu/lantern/src/github.com/getlantern/pac/pac_bytes_linux_mips.go cp /home/ubuntu/lantern/src/github.com/getlantern/pac/pac_bytes_linux_386.go /home/ubuntu/lantern/src/github.com/getlantern/pac/pac_bytes_linux_mipsle.go export VERSION=9.9.9
由于lantern使用了golang中部分在mipsle未实现的功能(主要是获取用户主目录的时候使用了user.Current()), 因此需要修改这部分代码.
~/lantern/src/github.com/getlantern/appdir/appdir.go
func InHomeDir(filename string) string { usr, err := user.Current() if err != nil { panic(fmt.Errorf("Unable to determine user's home directory: %s", err)) } return filepath.Join(usr.HomeDir, filename) }
修改为
func InHomeDir(filename string) string { usr, err := user.Current() if err != nil { log.Printf("[github.com/getlantern/appdir/appdir.go] Unable to determine user's home directory: %s, try $HOME as user's home directory", err) return filepath.Join(os.Getenv("HOME"), filename) } return filepath.Join(usr.HomeDir, filename) }
~/lantern/src/github.com/getlantern/byteexec/byteexec.go
func inHomeDir(filename string) (string, error) { log.Tracef("Determining user's home directory") usr, err := user.Current() if err != nil { return "", fmt.Errorf("Unable to determine user's home directory: %s", err) } return filepath.Join(usr.HomeDir, filename), nil }
修改为
func inHomeDir(filename string) (string, error) { log.Tracef("Determining user's home directory") usr, err := user.Current() if err != nil { return filepath.Join(os.Getenv("HOME"), filename), nil } return filepath.Join(usr.HomeDir, filename), nil }
~/lantern/src/github.com/getlantern/keyman/keyman_trust_linux.go
func getUserNssdb() (string, error) { // get the user's home dir usr, err := user.Current() if err != nil { return "", fmt.Errorf("Unable to get current user: %s", err) } return "sql:" + usr.HomeDir + "/.pki/nssdb", nil }
修改为
func getUserNssdb() (string, error) { // get the user's home dir usr, err := user.Current() if err != nil { return "sql:" + os.Getenv("HOME") + "/.pki/nssdb", nil } return "sql:" + usr.HomeDir + "/.pki/nssdb", nil }
Makefile
第25行
GIT_REVISION := $(shell git describe --abbrev=0 --tags --exact-match 2> /dev/null || git rev-parse --short HEAD) GIT_REVISION_DATE := $(shell git show -s --format=%ci $(GIT_REVISION_SHORTCODE))
修改为
GIT_REVISION := 9.9.9 GIT_REVISION_DATE := 2018-11-15 00:54:06 -0800
第249行
linux-arm: $(RESOURCES_DOT_GO) $(SOURCES) @source setenv.bash && \ HEADLESS=1 && \ $(call build-tags) && \ CGO_ENABLED=1 CC=arm-linux-gnueabi-gcc CXX=arm-linux-gnueabi-g++ CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 go build -a -o lantern_linux_arm -tags="$$BUILD_TAGS" -ldflags="$(LDFLAGS) $$EXTRA_LDFLAGS -linkmode internal -extldflags \"-static\"" github.com/getlantern/flashlight/main windows: $(RESOURCES_DOT_GO) $(SOURCES) @source setenv.bash && \ $(call build-tags) && \ CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -a -o lantern_windows_386.exe -tags="$$BUILD_TAGS" -ldflags="$(LDFLAGS) $$EXTRA_LDFLAGS -H=windowsgui" github.com/getlantern/flashlight/main;
修改为
linux-arm: $(RESOURCES_DOT_GO) $(SOURCES) @source setenv.bash && \ HEADLESS=1 && \ $(call build-tags) && \ CGO_ENABLED=1 CC=arm-linux-gnueabi-gcc CXX=arm-linux-gnueabi-g++ CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 go build -a -o lantern_linux_arm -tags="$$BUILD_TAGS" -ldflags="$(LDFLAGS) $$EXTRA_LDFLAGS -linkmode internal -extldflags \"-static\"" github.com/getlantern/flashlight/main linux-mipsle: $(RESOURCES_DOT_GO) $(SOURCES) @source setenv.bash && \ HEADLESS=1 && \ $(call build-tags) && \ CGO_ENABLED=1 CC=mipsel-linux-gnu-gcc CXX=mipsel-linux-gnu-g++ CGO_ENABLED=1 GOOS=linux GOARCH=mipsle go build -a -o lantern_linux_mipsle -tags="$$BUILD_TAGS" -ldflags="$(LDFLAGS) $$EXTRA_LDFLAGS -linkmode external -extldflags \"-static\"" github.com/getlantern/flashlight/main windows: $(RESOURCES_DOT_GO) $(SOURCES) @source setenv.bash && \ $(call build-tags) && \ CGO_ENABLED=1 GOOS=windows GOARCH=386 go build -a -o lantern_windows_386.exe -tags="$$BUILD_TAGS" -ldflags="$(LDFLAGS) $$EXTRA_LDFLAGS -H=windowsgui" github.com/getlantern/flashlight/main;
lantern 修改完成
cd /home/ubuntu/lantern/ make linux-mipsle
得到
lantern_linux_mipsle
, 大小有15M左右, 可以使用upx压缩,压缩后大小在5M左右.
注: 编译后得到的mipsle版lantern无法使用pac功能.在路由器上运行
我这里使用的路由器为 小米路由mini, 使用的系统为在 http://www.right.com.cn/forum/thread-161324-1-1.html 下载的Padavan固件, 插入一个8G大的U盘, 卷标为LY.
mkdir /media/LY/temp dd if=/dev/zero of=/media/LY/temp/swapfile count=200000 chmod 777 /media/LY/temp/swapfile mkswap /media/LY/temp/swapfile swapon /media/LY/temp/swapfile chmod +x /media/LY/temp/lantern_linux_mipsle ./lantern_linux_mipsle -proxyall &> ./lantern.log &
lantern运行成功, 可使用netstat -lntp查看是否8787和8788端口被lantern占用
运行截图
伸手党来了. 这些涉及fix有没有patch或者编译完成的lantern....我CPU和你的一样子的.
@hzexe
https://github.com/ilanyu/lantern/releases/download/4.5.9-bin/lantern_linux_mipsle