vpn.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  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. // Filesystem related stuff. Skipping when testing.
  411. if !Testing {
  412. // Clean and then create and write rendered ccd data.
  413. err = os.RemoveAll(_DefaultVPNCCDPath)
  414. if err != nil {
  415. if os.IsNotExist(err) {
  416. } else {
  417. return err
  418. }
  419. }
  420. if _, err := os.Stat(_DefaultVPNCCDPath); err != nil {
  421. }
  422. err = os.Mkdir(_DefaultVPNCCDPath, 0755)
  423. if err != nil {
  424. if !os.IsExist(err) {
  425. return err
  426. }
  427. }
  428. }
  429. // Render ccd templates for the users.
  430. for _, user := range users {
  431. var associatedRoutes [][3]string
  432. for _, network := range GetAllNetworks() {
  433. switch network.Type {
  434. case ROUTE:
  435. for _, assocUsername := range network.GetAssociatedUsernames() {
  436. if assocUsername == user.Username {
  437. via := network.Via
  438. ip, mask, err := net.ParseCIDR(network.CIDR)
  439. if err != nil {
  440. return err
  441. }
  442. associatedRoutes = append(associatedRoutes, [3]string{ip.To4().String(), net.IP(mask.Mask).To4().String(), via})
  443. }
  444. }
  445. }
  446. }
  447. var result bytes.Buffer
  448. params := struct {
  449. IP string
  450. NetMask string
  451. Routes [][3]string // [0] is IP, [1] is Netmask, [2] is Via
  452. RedirectGW bool
  453. }{IP: user.getIP().String(), NetMask: _DefaultServerNetMask, Routes: associatedRoutes, RedirectGW: !user.NoGW}
  454. data, err := bindata.Asset("template/ccd.file.tmpl")
  455. if err != nil {
  456. return err
  457. }
  458. t, err := template.New("ccd.file.tmpl").Parse(string(data))
  459. if err != nil {
  460. return fmt.Errorf("can not parse ccd.file.tmpl template: %s", err)
  461. }
  462. err = t.Execute(&result, params)
  463. if err != nil {
  464. return fmt.Errorf("can not render ccd file %s: %s", user.Username, err)
  465. }
  466. err = emitToFile(_DefaultVPNCCDPath+user.Username, result.String(), 0)
  467. if err != nil {
  468. return err
  469. }
  470. }
  471. return nil
  472. }
  473. func emitDHParams() error {
  474. var result bytes.Buffer
  475. data, err := bindata.Asset("template/dh4096.pem.tmpl")
  476. if err != nil {
  477. return err
  478. }
  479. t, err := template.New("dh4096.pem.tmpl").Parse(string(data))
  480. if err != nil {
  481. return fmt.Errorf("can not parse dh4096.pem template: %s", err)
  482. }
  483. err = t.Execute(&result, nil)
  484. if err != nil {
  485. return fmt.Errorf("can not render dh4096.pem file: %s", err)
  486. }
  487. err = emitToFile(_DefaultDHParamsPath, result.String(), 0)
  488. if err != nil {
  489. return err
  490. }
  491. return nil
  492. }
  493. func emitIptables() error {
  494. if Testing {
  495. return nil
  496. }
  497. ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
  498. if err != nil {
  499. return fmt.Errorf("can not create new iptables object: %v", err)
  500. }
  501. for _, network := range GetAllNetworks() {
  502. associatedUsernames := network.GetAssociatedUsernames()
  503. switch network.Type {
  504. case SERVERNET:
  505. users, err := GetAllUsers()
  506. if err != nil {
  507. return err
  508. }
  509. for _, user := range users {
  510. var found bool
  511. for _, auser := range associatedUsernames {
  512. if user.Username == auser {
  513. found = true
  514. break
  515. }
  516. }
  517. userIP, _, err := net.ParseCIDR(user.GetIPNet())
  518. if err != nil {
  519. return err
  520. }
  521. _, networkIPNet, err := net.ParseCIDR(network.CIDR)
  522. if err != nil {
  523. return err
  524. }
  525. // get destination network's iface
  526. iface := interfaceOfIP(networkIPNet)
  527. if iface == nil {
  528. logrus.Warnf("network doesn't exist on server %s[SERVERNET]: cant find interface for %s", network.Name, networkIPNet.String())
  529. return nil
  530. }
  531. // enable nat for the user to the destination network n
  532. if found {
  533. err = ipt.AppendUnique("nat", "POSTROUTING", "-s", userIP.String(), "-o", iface.Name, "-j", "MASQUERADE")
  534. if err != nil {
  535. logrus.Error(err)
  536. return err
  537. }
  538. } else {
  539. err = ipt.Delete("nat", "POSTROUTING", "-s", userIP.String(), "-o", iface.Name, "-j", "MASQUERADE")
  540. if err != nil {
  541. logrus.Debug(err)
  542. }
  543. }
  544. }
  545. }
  546. }
  547. return nil
  548. }
  549. func checkOpenVPNExecutable() bool {
  550. executable := getOpenVPNExecutable()
  551. if executable == "" {
  552. logrus.Error("openvpn is not installed ✘")
  553. return false
  554. }
  555. logrus.Debugf("openvpn executable detected: %s ✔", executable)
  556. return true
  557. }
  558. func getOpenVPNExecutable() string {
  559. cmd := exec.Command("which", "openvpn")
  560. output, err := cmd.Output()
  561. if err != nil {
  562. logrus.Errorf("openvpn is not installed: %s ✘", err)
  563. return ""
  564. }
  565. logrus.Debugf("openvpn executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  566. return strings.TrimSpace(string(output[:]))
  567. }
  568. func checkOpenSSLExecutable() bool {
  569. cmd := exec.Command("which", "openssl")
  570. output, err := cmd.Output()
  571. if err != nil {
  572. logrus.Errorf("openssl is not installed: %s ✘", err)
  573. return false
  574. }
  575. logrus.Debugf("openssl executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  576. return true
  577. }
  578. func checkIptablesExecutable() bool {
  579. cmd := exec.Command("which", "iptables")
  580. output, err := cmd.Output()
  581. if err != nil {
  582. logrus.Errorf("iptables is not installed: %s ✘", err)
  583. return false
  584. }
  585. logrus.Debugf("iptables executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  586. return true
  587. }
  588. func ensureBaseDir() {
  589. if Testing {
  590. return
  591. }
  592. os.Mkdir(varBasePath, 0755)
  593. }
  594. func init() {
  595. ensureBaseDir()
  596. var err error
  597. vpnProc, err = supervisor.NewProcess(getOpenVPNExecutable(), varBasePath, []string{"--config", _DefaultVPNConfPath})
  598. if err != nil {
  599. logrus.Errorf("can not create process: %v", err)
  600. }
  601. }