handle_charon.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright 2015 flannel authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ipsec
  15. import (
  16. "fmt"
  17. "github.com/bronze1man/goStrongswanVici"
  18. "github.com/coreos/flannel/subnet"
  19. log "github.com/golang/glog"
  20. "golang.org/x/net/context"
  21. "net"
  22. "os"
  23. "os/exec"
  24. "strings"
  25. "sync"
  26. "syscall"
  27. "time"
  28. )
  29. const (
  30. charonExecutablePath = "/opt/strongswan/libexec/ipsec/charon"
  31. )
  32. var defaultViciUri = Uri{"unix", "/var/run/charon.vici"}
  33. type Uri struct {
  34. network, address string
  35. }
  36. type CharonIKEDaemon struct {
  37. viciUri Uri
  38. espProposal string
  39. }
  40. func NewCharonIKEDaemon(ctx context.Context, wg sync.WaitGroup, charonViciUri string,
  41. espProposal string) (*CharonIKEDaemon, error) {
  42. charon := &CharonIKEDaemon{viciUri: defaultViciUri, espProposal: espProposal}
  43. log.Infof("Using ESP proposal: %s", espProposal)
  44. if charonViciUri == "" {
  45. cmd, err := charon.runBundled()
  46. if err != nil {
  47. log.Errorf("Error starting bundled charon daemon: %v", err)
  48. return nil, err
  49. } else {
  50. log.Info("Bundled charon daemon started")
  51. }
  52. wg.Add(1)
  53. go func() {
  54. select {
  55. case <-ctx.Done():
  56. cmd.Process.Signal(syscall.SIGTERM)
  57. log.Infof("Stopped bundled charon daemon")
  58. wg.Done()
  59. return
  60. }
  61. }()
  62. } else {
  63. log.Infof("Using external charon at: %s", charonViciUri)
  64. addr := strings.Split(charonViciUri, "://")
  65. charon.viciUri = Uri{addr[0], addr[1]}
  66. }
  67. return charon, nil
  68. }
  69. func (charon *CharonIKEDaemon) getClient() (
  70. client *goStrongswanVici.ClientConn, err error) {
  71. conn, err := net.Dial(charon.viciUri.network, charon.viciUri.address)
  72. if err != nil {
  73. return
  74. }
  75. return goStrongswanVici.NewClientConn(conn), nil
  76. }
  77. func (charon *CharonIKEDaemon) runBundled() (cmd *exec.Cmd, err error) {
  78. path, err := exec.LookPath(charonExecutablePath)
  79. if err != nil {
  80. return nil, err
  81. }
  82. cmd = &exec.Cmd{
  83. Path: path,
  84. SysProcAttr: &syscall.SysProcAttr{
  85. Pdeathsig: syscall.SIGTERM,
  86. },
  87. }
  88. cmd.Stderr = os.Stderr
  89. err = cmd.Start()
  90. return
  91. }
  92. func (charon *CharonIKEDaemon) LoadSharedKey(remotePublicIP, password string) error {
  93. var err error
  94. var client *goStrongswanVici.ClientConn
  95. for {
  96. client, err = charon.getClient()
  97. if err == nil {
  98. break
  99. } else {
  100. log.Error("ClientConnection failed: ", err)
  101. log.Info("Retrying in 1 second ...")
  102. time.Sleep(1 * time.Second)
  103. }
  104. }
  105. defer client.Close()
  106. sharedKey := &goStrongswanVici.Key{
  107. Typ: "IKE",
  108. Data: password,
  109. Owners: []string{remotePublicIP},
  110. }
  111. err = client.LoadShared(sharedKey)
  112. if err != nil {
  113. return err
  114. }
  115. log.Infof("Loaded shared key for: %v", remotePublicIP)
  116. return nil
  117. }
  118. func (charon *CharonIKEDaemon) LoadConnection(localLease, remoteLease *subnet.Lease,
  119. reqID, encap string) error {
  120. var err error
  121. var client *goStrongswanVici.ClientConn
  122. for {
  123. client, err = charon.getClient()
  124. if err == nil {
  125. break
  126. } else {
  127. log.Info("ClientConnection failed: ", err)
  128. log.Infof("Retying in 1 second ...")
  129. time.Sleep(1 * time.Second)
  130. }
  131. }
  132. defer client.Close()
  133. childConfMap := make(map[string]goStrongswanVici.ChildSAConf)
  134. childSAConf := goStrongswanVici.ChildSAConf{
  135. Local_ts: []string{localLease.Subnet.String()},
  136. Remote_ts: []string{remoteLease.Subnet.String()},
  137. ESPProposals: []string{charon.espProposal},
  138. StartAction: "start",
  139. CloseAction: "trap",
  140. Mode: "tunnel",
  141. ReqID: reqID,
  142. // RekeyTime: rekeyTime,
  143. InstallPolicy: "no",
  144. }
  145. childSAConfName := formatChildSAConfName(localLease, remoteLease)
  146. childConfMap[childSAConfName] = childSAConf
  147. localAuthConf := goStrongswanVici.AuthConf{
  148. AuthMethod: "psk",
  149. }
  150. remoteAuthConf := goStrongswanVici.AuthConf{
  151. AuthMethod: "psk",
  152. }
  153. ikeConf := goStrongswanVici.IKEConf{
  154. LocalAddrs: []string{localLease.Attrs.PublicIP.String()},
  155. RemoteAddrs: []string{remoteLease.Attrs.PublicIP.String()},
  156. Proposals: []string{"aes256-sha256-modp4096"},
  157. Version: "2",
  158. KeyingTries: "0", //continues to retry
  159. LocalAuth: localAuthConf,
  160. RemoteAuth: remoteAuthConf,
  161. Children: childConfMap,
  162. Encap: encap,
  163. }
  164. ikeConfMap := make(map[string]goStrongswanVici.IKEConf)
  165. connectionName := formatConnectionName(localLease, remoteLease)
  166. ikeConfMap[connectionName] = ikeConf
  167. err = client.LoadConn(&ikeConfMap)
  168. if err != nil {
  169. return err
  170. }
  171. log.Infof("Loaded connection: %v", connectionName)
  172. return nil
  173. }
  174. func (charon *CharonIKEDaemon) UnloadCharonConnection(localLease,
  175. remoteLease *subnet.Lease) error {
  176. client, err := charon.getClient()
  177. if err != nil {
  178. return err
  179. }
  180. defer client.Close()
  181. connectionName := formatConnectionName(localLease, remoteLease)
  182. unloadConnRequest := &goStrongswanVici.UnloadConnRequest{
  183. Name: connectionName,
  184. }
  185. err = client.UnloadConn(unloadConnRequest)
  186. if err != nil {
  187. return err
  188. }
  189. log.Infof("Unloaded connection: %v", connectionName)
  190. return nil
  191. }
  192. func formatConnectionName(localLease, remoteLease *subnet.Lease) string {
  193. return fmt.Sprintf("%s-%s-%s-%s", localLease.Attrs.PublicIP,
  194. localLease.Subnet, remoteLease.Subnet, remoteLease.Attrs.PublicIP)
  195. }
  196. func formatChildSAConfName(localLease, remoteLease *subnet.Lease) string {
  197. return fmt.Sprintf("%s-%s", localLease.Subnet, remoteLease.Subnet)
  198. }