summaryrefslogtreecommitdiff
path: root/pkg/vpn/main.go
blob: 3db2f15dd5643a196f37a4df69733e127ff83733 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (C) 2018-2020 LEAP
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package vpn

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net"
	"os"
	"time"

	"0xacab.org/leap/bitmask-vpn/pkg/config"
	"0xacab.org/leap/bitmask-vpn/pkg/config/version"
	"0xacab.org/leap/bitmask-vpn/pkg/motd"
	"0xacab.org/leap/bitmask-vpn/pkg/snowflake"
	"0xacab.org/leap/bitmask-vpn/pkg/vpn/bonafide"
	"github.com/apparentlymart/go-openvpn-mgmt/openvpn"
)

// Bitmask holds the bitmask client data
type Bitmask struct {
	tempdir          string
	onGateway        bonafide.Gateway
	ptGateway        bonafide.Gateway
	statusCh         chan string
	managementClient *openvpn.MgmtClient
	bonafide         *bonafide.Bonafide
	launch           *launcher
	transport        string
	listener         net.Listener
	certPemPath      string
	openvpnArgs      []string
	udp              bool
	snowflake        bool
	offersUdp        bool
	failed           bool
	canUpgrade       bool
	motd             []motd.Message
	provider         string
}

// Init the connection to bitmask
func Init() (*Bitmask, error) {
	statusCh := make(chan string, 10)
	tempdir, err := ioutil.TempDir("", "leap-")
	if err != nil {
		return nil, err
	}
	snowCh := make(chan *snowflake.StatusEvent, 20)
	bf := bonafide.New()
	bf.SnowflakeCh = snowCh
	launch, err := newLauncher()
	if err != nil {
		return nil, err
	}

	b := Bitmask{
		tempdir,
		bonafide.Gateway{},
		bonafide.Gateway{}, statusCh, nil, bf, launch,
		"", nil, "", []string{},
		false, false, false, false, false,
		[]motd.Message{}, ""}
	// FIXME multiprovider: need to pass provider name early on
	// XXX we want to block on these, but they can timeout if we're blocked.
	b.checkForUpgrades()
	b.checkForMOTD()
	b.launch.firewallStop()
	/*
		TODO -- we still want to do this, since it resets the fw/vpn if running
		from a previous one, but first we need to complete all the
		system/helper checks that we can do. otherwise this times out with an
		error that's captured badly as of today.

			err = b.StopVPN()
			if err != nil {
				return nil, err
			}
	*/

	err = ioutil.WriteFile(b.getTempCaCertPath(), config.CaCert, 0600)
	go b.fetchGateways()
	go b.openvpnManagement()

	return &b, err
}

func (b *Bitmask) SetProvider(p string) {
	b.provider = p
}

func (b *Bitmask) checkForUpgrades() {

	// SNAPS have their own way of upgrading. We probably should also try to detect
	// if we've been installed via another package manager.
	// For now, it's maybe a good idea to disable the UI check in linux, and be
	// way more strict in windows/osx.
	if os.Getenv("SNAP") != "" {
		return
	}
	b.canUpgrade = version.CanUpgrade()
}

func (b *Bitmask) checkForMOTD() {
	b.motd = motd.FetchLatest()
}

// GetStatusCh returns a channel that will recieve VPN status changes
func (b *Bitmask) GetStatusCh() <-chan string {
	return b.statusCh
}

func (b *Bitmask) GetSnowflakeCh() <-chan *snowflake.StatusEvent {
	return b.bonafide.SnowflakeCh
}

// Close the connection to bitmask, and does cleanup of temporal files
func (b *Bitmask) Close() {
	log.Printf("Close: cleanup and vpn shutdown...")
	b.StopVPN()
	time.Sleep(500 * time.Millisecond)
	err := b.launch.close()
	if err != nil {
		log.Printf("There was an error closing the launcher: %v", err)
	}
	err = os.RemoveAll(b.tempdir)
	if err != nil {
		log.Printf("There was an error removing temp dir: %v", err)
	}
}

// Version gets the bitmask version string
func (b *Bitmask) Version() (string, error) {
	return "", nil
}

func (b *Bitmask) NeedsCredentials() bool {
	return b.bonafide.NeedsCredentials()
}

func (b *Bitmask) DoLogin(username, password string) (bool, error) {
	return b.bonafide.DoLogin(username, password)
}

func (b *Bitmask) UseUDP(udp bool) error {
	b.udp = udp
	return nil
}

func (b *Bitmask) UseSnowflake(s bool) error {
	b.snowflake = s
	return nil
}

func (b *Bitmask) OffersUDP() bool {
	return b.bonafide.IsUDPAvailable()
}

func (b *Bitmask) GetMotd() string {
	bytes, err := json.Marshal(b.motd)
	if err != nil {
		log.Println("WARN error marshalling motd")
	}
	return string(bytes)
}

func (b *Bitmask) CanUpgrade() bool {
	return b.canUpgrade
}