编译mipsle版lantern

使用的环境为 腾讯云 Ubuntu Server 16.04.1 LTS 32位

  1. 安装依赖包

     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
    
  1. 由于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
     }
    

    源码修改完成
    下面编译修改后的golang

     GOROOT_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
    
  2. 编译 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功能.

  3. 在路由器上运行

    我这里使用的路由器为 小米路由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占用

运行截图

标签: none

仅有一条评论

  1. hzexe hzexe

    伸手党来了. 这些涉及fix有没有patch或者编译完成的lantern....我CPU和你的一样子的.

添加新评论