add ipv6 support
[vpn-setup] / vpn-server-setup
1 #!/bin/bash -x
2 # Copyright (C) 2016 Ian Kelling
3
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16
17 set -eE -o pipefail
18 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
19
20 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
21
22 usage() {
23 cat <<'EOF'
24 usage: ${0##*/} [-d|-h|--help] [IPV6_ADDR/BITS IPV6_DEFAULT_ROUTE]
25
26 -r Do not push default route
27 -d Do not push dns
28 -s Do not start openvpn
29 -h --help print help
30
31 Sets up a vpn server which pushes gateway route and dns server so all
32 traffic goes through the vpn. requires systemd, and might have some
33 debian specific paths.
34
35 For ipv6, we assume ipv6_addr routes to the server.
36
37 You can save all the keys by storing /etc/openvpn/easy-rsa/keys, and
38 the script will not generate them if it sees they exist already.
39
40 Note: Uses GNU getopt options parsing style
41 EOF
42 exit $1
43 }
44
45 dns=true
46 route=true
47 start=true
48 temp=$(getopt -l help drsh "$@") || usage 1
49 eval set -- "$temp"
50 while true; do
51 case $1 in
52 -d) dns=false; shift ;;
53 -r) route=false; shift ;;
54 -s) start=false; shift ;;
55 -h|--help) usage ;;
56 --) shift; break ;;
57 *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
58 esac
59 done
60
61 read -r ip6 ip6route <<<"$@"
62
63
64 apt-get update
65 # suggests get's us openssl. policy-rc.d is to prevent install from starting services
66 f=/usr/sbin/policy-rc.d;
67 dd of=$f <<EOF
68 #!/bin/sh
69 exit 101
70 EOF
71 chmod +x $f;
72 apt-get install --install-suggests -y openvpn
73 rm $f
74
75 if [[ -e /lib/systemd/system/openvpn-server@.service ]]; then
76 vpn_service=openvpn-server@server
77 else
78 vpn_service=openvpn@server
79 fi
80 apt-get install -y uuid-runtime easy-rsa
81 mkdir -p /etc/openvpn/easy-rsa
82 cd /etc/openvpn/easy-rsa
83 cp -r /usr/share/easy-rsa/* .
84 if [[ -e openssl-1.0.0.cnf && ! -e openssl.cnf ]]; then
85 # there's a debian bug about this.
86 ln -s openssl-1.0.0.cnf openssl.cnf
87 fi
88
89 server_dir=/etc/openvpn/server
90 mkdir -p $server_dir
91 chmod 700 $server_dir
92
93
94 new=true
95 keyfiles=(/etc/openvpn/easy-rsa/pki/{ca.crt,private/server.key,issued/server.crt})
96 if [[ -e /etc/openvpn/easy-rsa/build-ca ]]; then
97 new=false
98 keyfiles=(/etc/openvpn/easy-rsa/keys/{ca.crt,server.{crt,key}})
99 fi
100
101 keys_exist=true
102 for f in ${keyfiles[@]}; do
103 if [[ ! -e $f ]]; then
104 keys_exist=false
105 break
106 fi
107 done
108
109 if ! $keys_exist; then
110 # newer sample configs (post stretch) use ta.key. no harm making it for earlier oses
111 openvpn --genkey --secret $server_dir/ta.key
112 if $new; then
113 ./easyrsa init-pki
114 ./easyrsa --batch build-ca nopass
115 ./easyrsa build-server-full server nopass
116 openssl dhparam -out $server_dir/dh2048.pem 2048
117 else
118 # dun care about settning cert cn etc from the non-example values
119 source vars
120 # doesnt exist in buster
121 ./clean-all # note: removes and creates /etc/openvpn/easy-rsa/keys
122 # accept default prompts
123 echo -e '\n\n\n\n\n\n\n\n' | ./build-ca
124
125 # This builds the server's key/cert. argument is the name of the file,
126 # but it also is the default common name of the cert.
127 # 'server' is the default name in our conf file for the name of the file
128 # and I've seen no reason to change it.
129 # Note, this is not idempotent.
130 { echo -e '\n\n\n\n\n\n\n\n\n\n'; sleep 1; echo -e 'y\ny\n'; } | ./build-key-server server
131 ./build-dh
132 fi
133 fi
134
135
136 cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz $server_dir
137 gzip -df $server_dir/server.conf.gz
138
139
140 cp ${keyfiles[@]} $server_dir
141 # for legacy systems
142 for f in ${keyfiles[@]}; do
143 ln -sf server/${f##*/} /etc/openvpn
144 done
145
146 cat >>$server_dir/server.conf <<'EOF'
147
148 # I cat an extra blank line to start because the example config does
149 # not have a final newline. ....
150
151 # not in example config, but openvpn outputs a warning about insecure
152 # cipher without a setting like this (the default i can understand due
153 # to compatibility issues, but not changing the example config... not
154 # cool).
155 # requires the same setting on the client side.
156 cipher AES-256-CBC
157 # just sets up the ability to have client specific configs
158 client-config-dir /etc/openvpn/client-config
159
160 # duplicate in newer sample configs
161 tls-auth ta.key 0 # This file is secret
162
163 # depending on sample config, this may not be there, which means i can't
164 # talk to 10.8.0.1, there might be some other way, but stretch's
165 # sample config says:
166 # Should be subnet (addressing via IP)
167 # unless Windows clients v2.0.9 and lower have to
168 # be supported (then net30, i.e. a /30 per client)
169 # Defaults to net30 (not recommended)
170 topology subnet
171 EOF
172
173
174 # dh improve security,
175 # remove comp-lzo to increase perf
176 sed -i --follow-symlinks -f - $server_dir/server.conf <<'EOF'
177 s/^dh dh1024.pem/dh dh2048.pem/
178 /^comp-lzo.*/d
179 EOF
180
181
182 mkdir -p /etc/openvpn/client-config
183
184
185 if $dns; then
186 # Be the dns server for clients
187 cat >>$server_dir/server.conf <<'EOF'
188 push "dhcp-option DNS 10.8.0.1"
189 EOF
190 fi
191
192 if $ip6; then
193 cat >>$server_dir/server.conf <<EOF
194 push tun-ipv6 # legacy option that flidas needs, has no harm.
195 ifconfig-ipv6 $ip6 $ip6_route
196 EOF
197 fi
198
199
200 if $route; then
201 cat >>$server_dir/server.conf <<'EOF'
202 # Be the default gateway for clients.
203 push "redirect-gateway def1"
204 EOF
205 if $ip6; then
206 cat >>$server_dir/server.conf <<'EOF'
207 push "route-ipv6 2000::/3"
208 EOF
209 fi
210 fi
211
212 sed -i --follow-symlinks '/^ *net\.ipv4\.ip_forward=.*/d' /etc/sysctl.conf
213 sed -i --follow-symlinks '/^ *net.ipv6.conf.all.forwarding=.*/d' /etc/sysctl.conf
214 cat >>/etc/sysctl.conf <<'EOF'
215 net.ipv4.ip_forward=1
216 net.ipv6.conf.all.forwarding=1
217 EOF
218 sysctl -p /etc/sysctl.conf
219
220 gw=$(ip route | sed -rn 's/^default via .* dev (\S+).*/\1/p')
221
222 cat >/etc/systemd/system/vpnnat.service <<EOF
223 [Unit]
224 Description=Turns on nat iptables setting
225
226 [Service]
227 Type=oneshot
228 RemainAfterExit=yes
229 ExecStart=/sbin/iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o $gw -j MASQUERADE
230 ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o $gw -j MASQUERADE
231
232 [Install]
233 WantedBy=$vpn_service.service
234 EOF
235 systemctl daemon-reload # needed if the file was already there
236 # note, no need to start it, the vpn_service does that.
237 systemctl enable vpnnat
238
239 if $start; then
240 systemctl enable $vpn_service
241 systemctl restart $vpn_service
242 fi