vpn.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. //go:generate go-bindata -pkg bindata -o bindata/bindata.go template/
  2. //go:generate protoc -I pb/ pb/user.proto pb/vpn.proto pb/network.proto --go_out=plugins=grpc:pb
  3. package ovpm
  4. import (
  5. "bytes"
  6. "fmt"
  7. "math/big"
  8. "net"
  9. "os"
  10. "os/exec"
  11. "strings"
  12. "text/template"
  13. "time"
  14. "github.com/Sirupsen/logrus"
  15. "github.com/asaskevich/govalidator"
  16. "github.com/cad/ovpm/bindata"
  17. "github.com/cad/ovpm/pki"
  18. "github.com/cad/ovpm/supervisor"
  19. "github.com/coreos/go-iptables/iptables"
  20. "github.com/google/uuid"
  21. "github.com/jinzhu/gorm"
  22. )
  23. // DBServer is database model for storing VPN server related stuff.
  24. type DBServer struct {
  25. gorm.Model
  26. Name string `gorm:"unique_index"` // Server name.
  27. SerialNumber string
  28. Hostname string // Server's ip address or FQDN
  29. Port string // Server's listening port
  30. Cert string // Server RSA certificate.
  31. Key string // Server RSA private key.
  32. CACert string // Root CA RSA certificate.
  33. CAKey string // Root CA RSA key.
  34. Net string // VPN network.
  35. Mask string // VPN network mask.
  36. CRL string // Certificate Revocation List
  37. }
  38. // CheckSerial takes a serial number and checks it against the current server's serial number.
  39. func (s *DBServer) CheckSerial(serial string) bool {
  40. return serial == s.SerialNumber
  41. }
  42. type _VPNServerConfig struct {
  43. CertPath string
  44. KeyPath string
  45. CACertPath string
  46. CAKeyPath string
  47. CCDPath string
  48. CRLPath string
  49. DHParamsPath string
  50. Net string
  51. Mask string
  52. Port string
  53. }
  54. // Init regenerates keys and certs for a Root CA, and saves them in the database.
  55. func Init(hostname string, port string) error {
  56. if port == "" {
  57. port = DefaultVPNPort
  58. }
  59. if !govalidator.IsNumeric(port) {
  60. return fmt.Errorf("validation error: port:`%s` should be numeric", port)
  61. }
  62. serverName := "default"
  63. if IsInitialized() {
  64. if err := Deinit(); err != nil {
  65. logrus.Errorf("server can not be deleted: %v", err)
  66. return err
  67. }
  68. }
  69. if !govalidator.IsHost(hostname) {
  70. return fmt.Errorf("validation error: hostname:`%s` should be either an ip address or a FQDN", hostname)
  71. }
  72. ca, err := pki.NewCA()
  73. if err != nil {
  74. return fmt.Errorf("can not create ca creds: %s", err)
  75. }
  76. srv, err := pki.NewServerCertHolder(ca)
  77. if err != nil {
  78. return fmt.Errorf("can not create server cert creds: %s", err)
  79. }
  80. serialNumber := uuid.New().String()
  81. serverInstance := DBServer{
  82. Name: serverName,
  83. SerialNumber: serialNumber,
  84. Hostname: hostname,
  85. Port: port,
  86. Cert: srv.Cert,
  87. Key: srv.Key,
  88. CACert: ca.Cert,
  89. CAKey: ca.Key,
  90. Net: _DefaultServerNetwork,
  91. Mask: _DefaultServerNetMask,
  92. }
  93. db.Create(&serverInstance)
  94. if db.NewRecord(&serverInstance) {
  95. return fmt.Errorf("can not create server instance on database")
  96. }
  97. users, err := GetAllUsers()
  98. if err != nil {
  99. return err
  100. }
  101. // Sign all users in the db with the new server
  102. for _, user := range users {
  103. err := user.Renew()
  104. logrus.Infof("user certificate changed for %s, you should run: $ ovpm user export-config --user %s", user.Username, user.Username)
  105. if err != nil {
  106. logrus.Errorf("can not sign user %s: %v", user.Username, err)
  107. continue
  108. }
  109. }
  110. Emit()
  111. logrus.Infof("server initialized")
  112. return nil
  113. }
  114. // Deinit deletes the server with the given serverName from the database and frees the allocated resources.
  115. func Deinit() error {
  116. if !IsInitialized() {
  117. return fmt.Errorf("server not found")
  118. }
  119. db.Unscoped().Delete(&DBServer{})
  120. db.Unscoped().Delete(&DBRevoked{})
  121. Emit()
  122. return nil
  123. }
  124. // DumpsClientConfig generates .ovpn file for the given vpn user and returns it as a string.
  125. func DumpsClientConfig(username string) (string, error) {
  126. var result bytes.Buffer
  127. user, err := GetUser(username)
  128. if err != nil {
  129. return "", err
  130. }
  131. server, err := GetServerInstance()
  132. if err != nil {
  133. return "", err
  134. }
  135. params := struct {
  136. Hostname string
  137. Port string
  138. CA string
  139. Key string
  140. Cert string
  141. NoGW bool
  142. }{
  143. Hostname: server.Hostname,
  144. Port: server.Port,
  145. CA: server.CACert,
  146. Key: user.Key,
  147. Cert: user.Cert,
  148. NoGW: user.NoGW,
  149. }
  150. data, err := bindata.Asset("template/client.ovpn.tmpl")
  151. if err != nil {
  152. return "", err
  153. }
  154. t, err := template.New("client.ovpn").Parse(string(data))
  155. if err != nil {
  156. return "", fmt.Errorf("can not parse client.ovpn.tmpl template: %s", err)
  157. }
  158. err = t.Execute(&result, params)
  159. if err != nil {
  160. return "", fmt.Errorf("can not render client.ovpn: %s", err)
  161. }
  162. return result.String(), nil
  163. }
  164. // DumpClientConfig generates .ovpn file for the given vpn user and dumps it to outPath.
  165. func DumpClientConfig(username, path string) error {
  166. result, err := DumpsClientConfig(username)
  167. if err != nil {
  168. return err
  169. }
  170. // Wite rendered content into openvpn server conf.
  171. return emitToFile(path, result, 0)
  172. }
  173. // GetSystemCA returns the system CA from the database if available.
  174. func GetSystemCA() (*pki.CA, error) {
  175. server := DBServer{}
  176. db.First(&server)
  177. if db.NewRecord(&server) {
  178. return nil, fmt.Errorf("server record does not exists in db")
  179. }
  180. return &pki.CA{
  181. CertHolder: pki.CertHolder{
  182. Cert: server.CACert,
  183. Key: server.CAKey,
  184. },
  185. }, nil
  186. }
  187. // vpnProc represents the OpenVPN process that is managed by the ovpm supervisor globally OpenVPN.
  188. var vpnProc supervisor.Supervisable
  189. // StartVPNProc starts the OpenVPN process.
  190. func StartVPNProc() {
  191. if !IsInitialized() {
  192. logrus.Error("can not launch OpenVPN because system is not initialized")
  193. return
  194. }
  195. if vpnProc == nil {
  196. panic(fmt.Sprintf("vpnProc is not initialized!"))
  197. }
  198. if vpnProc.Status() == supervisor.RUNNING {
  199. logrus.Error("OpenVPN is already started")
  200. return
  201. }
  202. vpnProc.Start()
  203. ensureNatEnabled()
  204. }
  205. // RestartVPNProc restarts the OpenVPN process.
  206. func RestartVPNProc() {
  207. if !IsInitialized() {
  208. logrus.Error("can not launch OpenVPN because system is not initialized")
  209. return
  210. }
  211. if vpnProc == nil {
  212. panic(fmt.Sprintf("vpnProc is not initialized!"))
  213. }
  214. vpnProc.Restart()
  215. ensureNatEnabled()
  216. }
  217. // StopVPNProc stops the OpenVPN process.
  218. func StopVPNProc() {
  219. if vpnProc == nil {
  220. panic(fmt.Sprintf("vpnProc is not initialized!"))
  221. }
  222. if vpnProc.Status() != supervisor.RUNNING {
  223. logrus.Error("OpenVPN is already not running")
  224. return
  225. }
  226. vpnProc.Stop()
  227. }
  228. // Emit generates all needed files for the OpenVPN server and dumps them to their corresponding paths defined in the config.
  229. func Emit() error {
  230. // Check dependencies
  231. if !checkOpenVPNExecutable() {
  232. return fmt.Errorf("openvpn executable can not be found! you should install OpenVPN on this machine")
  233. }
  234. if !checkOpenSSLExecutable() {
  235. return fmt.Errorf("openssl executable can not be found! you should install openssl on this machine")
  236. }
  237. if !checkIptablesExecutable() {
  238. return fmt.Errorf("iptables executable can not be found")
  239. }
  240. if !IsInitialized() {
  241. return fmt.Errorf("you should create a server first. e.g. $ ovpm vpn create-server")
  242. }
  243. if err := emitServerConf(); err != nil {
  244. return fmt.Errorf("can not emit server conf: %s", err)
  245. }
  246. if err := emitServerCert(); err != nil {
  247. return fmt.Errorf("can not emit server cert: %s", err)
  248. }
  249. if err := emitServerKey(); err != nil {
  250. return fmt.Errorf("can not emit server key: %s", err)
  251. }
  252. if err := emitCACert(); err != nil {
  253. return fmt.Errorf("can not emit ca cert : %s", err)
  254. }
  255. if err := emitCAKey(); err != nil {
  256. return fmt.Errorf("can not emit ca key: %s", err)
  257. }
  258. if err := emitDHParams(); err != nil {
  259. return fmt.Errorf("can not emit dhparams: %s", err)
  260. }
  261. if err := emitCCD(); err != nil {
  262. return fmt.Errorf("can not emit ccd: %s", err)
  263. }
  264. if err := emitIptables(); err != nil {
  265. return fmt.Errorf("can not emit iptables: %s", err)
  266. }
  267. if err := emitCRL(); err != nil {
  268. return fmt.Errorf("can not emit crl: %s", err)
  269. }
  270. logrus.Info("configurations emitted to the filesystem")
  271. if IsInitialized() {
  272. for {
  273. if vpnProc.Status() == supervisor.RUNNING || vpnProc.Status() == supervisor.STOPPED {
  274. logrus.Info("OpenVPN process is restarting")
  275. RestartVPNProc()
  276. break
  277. }
  278. time.Sleep(1 * time.Second)
  279. }
  280. }
  281. return nil
  282. }
  283. func emitToFile(path, content string, mode uint) error {
  284. // When testing don't emit files to the filesystem. Just pretend you did.
  285. if Testing {
  286. return nil
  287. }
  288. file, err := os.Create(path)
  289. if err != nil {
  290. return fmt.Errorf("Cannot create file %s: %v", path, err)
  291. }
  292. if mode != 0 {
  293. file.Chmod(os.FileMode(mode))
  294. }
  295. defer file.Close()
  296. fmt.Fprintf(file, content)
  297. return nil
  298. }
  299. func emitServerConf() error {
  300. serverInstance, err := GetServerInstance()
  301. if err != nil {
  302. return fmt.Errorf("can not retrieve server: %v", err)
  303. }
  304. port := DefaultVPNPort
  305. if serverInstance.Port != "" {
  306. port = serverInstance.Port
  307. }
  308. var result bytes.Buffer
  309. server := _VPNServerConfig{
  310. CertPath: _DefaultCertPath,
  311. KeyPath: _DefaultKeyPath,
  312. CACertPath: _DefaultCACertPath,
  313. CAKeyPath: _DefaultCAKeyPath,
  314. CCDPath: _DefaultVPNCCDPath,
  315. CRLPath: _DefaultCRLPath,
  316. DHParamsPath: _DefaultDHParamsPath,
  317. Net: _DefaultServerNetwork,
  318. Mask: _DefaultServerNetMask,
  319. Port: port,
  320. }
  321. data, err := bindata.Asset("template/server.conf.tmpl")
  322. if err != nil {
  323. return err
  324. }
  325. t, err := template.New("server.conf").Parse(string(data))
  326. if err != nil {
  327. return fmt.Errorf("can not parse server.conf.tmpl template: %s", err)
  328. }
  329. err = t.Execute(&result, server)
  330. if err != nil {
  331. return fmt.Errorf("can not render server.conf: %s", err)
  332. }
  333. // Wite rendered content into openvpn server conf.
  334. return emitToFile(_DefaultVPNConfPath, result.String(), 0)
  335. }
  336. // GetServerInstance returns the default server from the database.
  337. func GetServerInstance() (*DBServer, error) {
  338. var server DBServer
  339. db.First(&server)
  340. if db.NewRecord(server) {
  341. return nil, fmt.Errorf("can not retrieve server from db")
  342. }
  343. return &server, nil
  344. }
  345. // IsInitialized checks if there is a default server in the database or not.
  346. func IsInitialized() bool {
  347. var server DBServer
  348. db.First(&server)
  349. if db.NewRecord(server) {
  350. return false
  351. }
  352. return true
  353. }
  354. func emitServerKey() error {
  355. server, err := GetServerInstance()
  356. if err != nil {
  357. return err
  358. }
  359. // Write rendered content into key file.
  360. return emitToFile(_DefaultKeyPath, server.Key, 0600)
  361. }
  362. func emitServerCert() error {
  363. server, err := GetServerInstance()
  364. if err != nil {
  365. return err
  366. }
  367. // Write rendered content into the cert file.
  368. return emitToFile(_DefaultCertPath, server.Cert, 0)
  369. }
  370. func emitCRL() error {
  371. var revokedDBItems []*DBRevoked
  372. db.Find(&revokedDBItems)
  373. var revokedCertSerials []*big.Int
  374. for _, item := range revokedDBItems {
  375. bi := big.NewInt(0)
  376. bi.SetString(item.SerialNumber, 16)
  377. revokedCertSerials = append(revokedCertSerials, bi)
  378. }
  379. systemCA, err := GetSystemCA()
  380. if err != nil {
  381. return fmt.Errorf("can not emit CRL: %v", err)
  382. }
  383. crl, err := pki.NewCRL(systemCA, revokedCertSerials...)
  384. if err != nil {
  385. return fmt.Errorf("can not emit crl: %v", err)
  386. }
  387. return emitToFile(_DefaultCRLPath, crl, 0)
  388. }
  389. func emitCACert() error {
  390. server, err := GetServerInstance()
  391. if err != nil {
  392. return err
  393. }
  394. // Write rendered content into the ca cert file.
  395. return emitToFile(_DefaultCACertPath, server.CACert, 0)
  396. }
  397. func emitCAKey() error {
  398. server, err := GetServerInstance()
  399. if err != nil {
  400. return err
  401. }
  402. // Write rendered content into the ca key file.
  403. return emitToFile(_DefaultCAKeyPath, server.CAKey, 0600)
  404. }
  405. func emitCCD() error {
  406. users, err := GetAllUsers()
  407. if err != nil {
  408. return err
  409. }
  410. if !Testing {
  411. // Clean and then create and write rendered ccd data.
  412. err = os.RemoveAll(_DefaultVPNCCDPath)
  413. if err != nil {
  414. if os.IsNotExist(err) {
  415. } else {
  416. return err
  417. }
  418. }
  419. if _, err := os.Stat(_DefaultVPNCCDPath); err != nil {
  420. }
  421. err = os.Mkdir(_DefaultVPNCCDPath, 0755)
  422. if err != nil {
  423. if !os.IsExist(err) {
  424. return err
  425. }
  426. }
  427. }
  428. for _, user := range users {
  429. var result bytes.Buffer
  430. params := struct {
  431. IP string
  432. NetMask string
  433. }{IP: user.getIP().String(), NetMask: _DefaultServerNetMask}
  434. data, err := bindata.Asset("template/ccd.file.tmpl")
  435. if err != nil {
  436. return err
  437. }
  438. t, err := template.New("ccd.file.tmpl").Parse(string(data))
  439. if err != nil {
  440. return fmt.Errorf("can not parse ccd.file.tmpl template: %s", err)
  441. }
  442. err = t.Execute(&result, params)
  443. if err != nil {
  444. return fmt.Errorf("can not render ccd file %s: %s", user.Username, err)
  445. }
  446. err = emitToFile(_DefaultVPNCCDPath+user.Username, result.String(), 0)
  447. if err != nil {
  448. return err
  449. }
  450. }
  451. return nil
  452. }
  453. func emitDHParams() error {
  454. var result bytes.Buffer
  455. data, err := bindata.Asset("template/dh4096.pem.tmpl")
  456. if err != nil {
  457. return err
  458. }
  459. t, err := template.New("dh4096.pem.tmpl").Parse(string(data))
  460. if err != nil {
  461. return fmt.Errorf("can not parse dh4096.pem template: %s", err)
  462. }
  463. err = t.Execute(&result, nil)
  464. if err != nil {
  465. return fmt.Errorf("can not render dh4096.pem file: %s", err)
  466. }
  467. err = emitToFile(_DefaultDHParamsPath, result.String(), 0)
  468. if err != nil {
  469. return err
  470. }
  471. return nil
  472. }
  473. func emitIptables() error {
  474. if Testing {
  475. return nil
  476. }
  477. ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
  478. if err != nil {
  479. return fmt.Errorf("can not create new iptables object: %v", err)
  480. }
  481. for _, network := range GetAllNetworks() {
  482. associatedUsernames := network.GetAssociatedUsernames()
  483. switch network.Type {
  484. case SERVERNET:
  485. users, err := GetAllUsers()
  486. if err != nil {
  487. return err
  488. }
  489. for _, user := range users {
  490. var found bool
  491. for _, auser := range associatedUsernames {
  492. if user.Username == auser {
  493. found = true
  494. break
  495. }
  496. }
  497. userIP, _, err := net.ParseCIDR(user.GetIPNet())
  498. if err != nil {
  499. return err
  500. }
  501. _, networkIPNet, err := net.ParseCIDR(network.CIDR)
  502. if err != nil {
  503. return err
  504. }
  505. // get destination network's iface
  506. iface := interfaceOfIP(networkIPNet)
  507. if iface == nil {
  508. return fmt.Errorf("cant find interface for %s", networkIPNet.String())
  509. }
  510. logrus.Debugf("emitIptables: net(%s) iface name '%s'", network.Name, iface.Name)
  511. logrus.Debugf("emitIptables: user '%s' ip addr '%s'", user.GetUsername(), userIP.String())
  512. // enable nat for the user to the destination network n
  513. if found {
  514. err = ipt.AppendUnique("nat", "POSTROUTING", "-s", userIP.String(), "-o", iface.Name, "-j", "MASQUERADE")
  515. if err != nil {
  516. logrus.Error(err)
  517. return err
  518. }
  519. } else {
  520. err = ipt.Delete("nat", "POSTROUTING", "-s", userIP.String(), "-o", iface.Name, "-j", "MASQUERADE")
  521. if err != nil {
  522. logrus.Debug(err)
  523. }
  524. }
  525. }
  526. }
  527. }
  528. return nil
  529. }
  530. func checkOpenVPNExecutable() bool {
  531. executable := getOpenVPNExecutable()
  532. if executable == "" {
  533. logrus.Error("openvpn is not installed ✘")
  534. return false
  535. }
  536. logrus.Debugf("openvpn executable detected: %s ✔", executable)
  537. return true
  538. }
  539. func getOpenVPNExecutable() string {
  540. cmd := exec.Command("which", "openvpn")
  541. output, err := cmd.Output()
  542. if err != nil {
  543. logrus.Errorf("openvpn is not installed: %s ✘", err)
  544. return ""
  545. }
  546. logrus.Debugf("openvpn executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  547. return strings.TrimSpace(string(output[:]))
  548. }
  549. func checkOpenSSLExecutable() bool {
  550. cmd := exec.Command("which", "openssl")
  551. output, err := cmd.Output()
  552. if err != nil {
  553. logrus.Errorf("openssl is not installed: %s ✘", err)
  554. return false
  555. }
  556. logrus.Debugf("openssl executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  557. return true
  558. }
  559. func checkIptablesExecutable() bool {
  560. cmd := exec.Command("which", "iptables")
  561. output, err := cmd.Output()
  562. if err != nil {
  563. logrus.Errorf("iptables is not installed: %s ✘", err)
  564. return false
  565. }
  566. logrus.Debugf("iptables executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  567. return true
  568. }
  569. func ensureBaseDir() {
  570. if Testing {
  571. return
  572. }
  573. os.Mkdir(varBasePath, 0755)
  574. }
  575. func init() {
  576. ensureBaseDir()
  577. var err error
  578. vpnProc, err = supervisor.NewProcess(getOpenVPNExecutable(), varBasePath, []string{"--config", _DefaultVPNConfPath})
  579. if err != nil {
  580. logrus.Errorf("can not create process: %v", err)
  581. }
  582. }