wireguard.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // Copyright 2019 the Kilo 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 wireguard
  15. import (
  16. "bytes"
  17. "fmt"
  18. "os/exec"
  19. "regexp"
  20. "sort"
  21. "strconv"
  22. "github.com/vishvananda/netlink"
  23. "gopkg.in/ini.v1"
  24. )
  25. type wgLink struct {
  26. a netlink.LinkAttrs
  27. t string
  28. }
  29. func (w wgLink) Attrs() *netlink.LinkAttrs {
  30. return &w.a
  31. }
  32. func (w wgLink) Type() string {
  33. return w.t
  34. }
  35. // New creates a new WireGuard interface.
  36. func New(prefix string) (int, error) {
  37. links, err := netlink.LinkList()
  38. if err != nil {
  39. return 0, fmt.Errorf("failed to list links: %v", err)
  40. }
  41. max := 0
  42. re := regexp.MustCompile(fmt.Sprintf("^%s([0-9]+)$", prefix))
  43. for _, link := range links {
  44. if matches := re.FindStringSubmatch(link.Attrs().Name); len(matches) == 2 {
  45. i, err := strconv.Atoi(matches[1])
  46. if err != nil {
  47. // This should never happen.
  48. return 0, fmt.Errorf("failed to parse digits as an integer: %v", err)
  49. }
  50. if i >= max {
  51. max = i + 1
  52. }
  53. }
  54. }
  55. name := fmt.Sprintf("%s%d", prefix, max)
  56. wl := wgLink{a: netlink.NewLinkAttrs(), t: "wireguard"}
  57. wl.a.Name = name
  58. if err := netlink.LinkAdd(wl); err != nil {
  59. return 0, fmt.Errorf("failed to create interface %s: %v", name, err)
  60. }
  61. link, err := netlink.LinkByName(name)
  62. if err != nil {
  63. return 0, fmt.Errorf("failed to get interface index: %v", err)
  64. }
  65. return link.Attrs().Index, nil
  66. }
  67. // Keys generates a WireGuard private and public key-pair.
  68. func Keys() ([]byte, []byte, error) {
  69. private, err := GenKey()
  70. if err != nil {
  71. return nil, nil, fmt.Errorf("failed to generate private key: %v", err)
  72. }
  73. public, err := PubKey(private)
  74. return private, public, err
  75. }
  76. // GenKey generates a WireGuard private key.
  77. func GenKey() ([]byte, error) {
  78. return exec.Command("wg", "genkey").Output()
  79. }
  80. // PubKey generates a WireGuard public key for a given private key.
  81. func PubKey(key []byte) ([]byte, error) {
  82. cmd := exec.Command("wg", "pubkey")
  83. stdin, err := cmd.StdinPipe()
  84. if err != nil {
  85. return nil, fmt.Errorf("failed to open pipe to stdin: %v", err)
  86. }
  87. go func() {
  88. defer stdin.Close()
  89. stdin.Write(key)
  90. }()
  91. public, err := cmd.Output()
  92. if err != nil {
  93. return nil, fmt.Errorf("failed to generate public key: %v", err)
  94. }
  95. return public, nil
  96. }
  97. // SetConf applies a WireGuard configuration file to the given interface.
  98. func SetConf(iface string, path string) error {
  99. cmd := exec.Command("wg", "setconf", iface, path)
  100. var stderr bytes.Buffer
  101. cmd.Stderr = &stderr
  102. if err := cmd.Run(); err != nil {
  103. return fmt.Errorf("failed to apply the WireGuard configuration: %s", stderr.String())
  104. }
  105. return nil
  106. }
  107. // ShowConf gets the WireGuard configuration for the given interface.
  108. func ShowConf(iface string) ([]byte, error) {
  109. cmd := exec.Command("wg", "showconf", iface)
  110. var stderr, stdout bytes.Buffer
  111. cmd.Stderr = &stderr
  112. cmd.Stdout = &stdout
  113. if err := cmd.Run(); err != nil {
  114. return nil, fmt.Errorf("failed to read the WireGuard configuration: %s", stderr.String())
  115. }
  116. return stdout.Bytes(), nil
  117. }
  118. // CompareConf compares two WireGuard configurations.
  119. // It returns true if they are equal, false if they are not,
  120. // and any error that was encountered.
  121. // Note: CompareConf only goes one level deep, as WireGuard
  122. // configurations are not nested further than that.
  123. func CompareConf(a, b []byte) (bool, error) {
  124. iniA, err := ini.Load(a)
  125. if err != nil {
  126. return false, fmt.Errorf("failed to parse configuration: %v", err)
  127. }
  128. iniB, err := ini.Load(b)
  129. if err != nil {
  130. return false, fmt.Errorf("failed to parse configuration: %v", err)
  131. }
  132. secsA, secsB := iniA.SectionStrings(), iniB.SectionStrings()
  133. if len(secsA) != len(secsB) {
  134. return false, nil
  135. }
  136. sort.Strings(secsA)
  137. sort.Strings(secsB)
  138. var keysA, keysB []string
  139. var valsA, valsB []string
  140. for i := range secsA {
  141. if secsA[i] != secsB[i] {
  142. return false, nil
  143. }
  144. keysA, keysB = iniA.Section(secsA[i]).KeyStrings(), iniB.Section(secsB[i]).KeyStrings()
  145. if len(keysA) != len(keysB) {
  146. return false, nil
  147. }
  148. sort.Strings(keysA)
  149. sort.Strings(keysB)
  150. for j := range keysA {
  151. if keysA[j] != keysB[j] {
  152. return false, nil
  153. }
  154. valsA, valsB = iniA.Section(secsA[i]).Key(keysA[j]).Strings(","), iniB.Section(secsB[i]).Key(keysB[j]).Strings(",")
  155. if len(valsA) != len(valsB) {
  156. return false, nil
  157. }
  158. sort.Strings(valsA)
  159. sort.Strings(valsB)
  160. for k := range valsA {
  161. if valsA[k] != valsB[k] {
  162. return false, nil
  163. }
  164. }
  165. }
  166. }
  167. return true, nil
  168. }