ssh.go 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. package nebula
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "flag"
  7. "fmt"
  8. "net"
  9. "os"
  10. "reflect"
  11. "runtime"
  12. "runtime/pprof"
  13. "sort"
  14. "strconv"
  15. "strings"
  16. "github.com/sirupsen/logrus"
  17. "github.com/slackhq/nebula/config"
  18. "github.com/slackhq/nebula/header"
  19. "github.com/slackhq/nebula/iputil"
  20. "github.com/slackhq/nebula/sshd"
  21. "github.com/slackhq/nebula/udp"
  22. )
  23. type sshListHostMapFlags struct {
  24. Json bool
  25. Pretty bool
  26. ByIndex bool
  27. }
  28. type sshPrintCertFlags struct {
  29. Json bool
  30. Pretty bool
  31. Raw bool
  32. }
  33. type sshPrintTunnelFlags struct {
  34. Pretty bool
  35. }
  36. type sshChangeRemoteFlags struct {
  37. Address string
  38. }
  39. type sshCloseTunnelFlags struct {
  40. LocalOnly bool
  41. }
  42. type sshCreateTunnelFlags struct {
  43. Address string
  44. }
  45. type sshDeviceInfoFlags struct {
  46. Json bool
  47. Pretty bool
  48. }
  49. func wireSSHReload(l *logrus.Logger, ssh *sshd.SSHServer, c *config.C) {
  50. c.RegisterReloadCallback(func(c *config.C) {
  51. if c.GetBool("sshd.enabled", false) {
  52. sshRun, err := configSSH(l, ssh, c)
  53. if err != nil {
  54. l.WithError(err).Error("Failed to reconfigure the sshd")
  55. ssh.Stop()
  56. }
  57. if sshRun != nil {
  58. go sshRun()
  59. }
  60. } else {
  61. ssh.Stop()
  62. }
  63. })
  64. }
  65. // configSSH reads the ssh info out of the passed-in Config and
  66. // updates the passed-in SSHServer. On success, it returns a function
  67. // that callers may invoke to run the configured ssh server. On
  68. // failure, it returns nil, error.
  69. func configSSH(l *logrus.Logger, ssh *sshd.SSHServer, c *config.C) (func(), error) {
  70. //TODO conntrack list
  71. //TODO print firewall rules or hash?
  72. listen := c.GetString("sshd.listen", "")
  73. if listen == "" {
  74. return nil, fmt.Errorf("sshd.listen must be provided")
  75. }
  76. _, port, err := net.SplitHostPort(listen)
  77. if err != nil {
  78. return nil, fmt.Errorf("invalid sshd.listen address: %s", err)
  79. }
  80. if port == "22" {
  81. return nil, fmt.Errorf("sshd.listen can not use port 22")
  82. }
  83. //TODO: no good way to reload this right now
  84. hostKeyPathOrKey := c.GetString("sshd.host_key", "")
  85. if hostKeyPathOrKey == "" {
  86. return nil, fmt.Errorf("sshd.host_key must be provided")
  87. }
  88. var hostKeyBytes []byte
  89. if strings.Contains(hostKeyPathOrKey, "-----BEGIN") {
  90. hostKeyBytes = []byte(hostKeyPathOrKey)
  91. } else {
  92. hostKeyBytes, err = os.ReadFile(hostKeyPathOrKey)
  93. if err != nil {
  94. return nil, fmt.Errorf("error while loading sshd.host_key file: %s", err)
  95. }
  96. }
  97. err = ssh.SetHostKey(hostKeyBytes)
  98. if err != nil {
  99. return nil, fmt.Errorf("error while adding sshd.host_key: %s", err)
  100. }
  101. // Clear existing trusted CAs and authorized keys
  102. ssh.ClearTrustedCAs()
  103. ssh.ClearAuthorizedKeys()
  104. rawCAs := c.GetStringSlice("sshd.trusted_cas", []string{})
  105. for _, caAuthorizedKey := range rawCAs {
  106. err := ssh.AddTrustedCA(caAuthorizedKey)
  107. if err != nil {
  108. l.WithError(err).WithField("sshCA", caAuthorizedKey).Warn("SSH CA had an error, ignoring")
  109. continue
  110. }
  111. }
  112. rawKeys := c.Get("sshd.authorized_users")
  113. keys, ok := rawKeys.([]interface{})
  114. if ok {
  115. for _, rk := range keys {
  116. kDef, ok := rk.(map[interface{}]interface{})
  117. if !ok {
  118. l.WithField("sshKeyConfig", rk).Warn("Authorized user had an error, ignoring")
  119. continue
  120. }
  121. user, ok := kDef["user"].(string)
  122. if !ok {
  123. l.WithField("sshKeyConfig", rk).Warn("Authorized user is missing the user field")
  124. continue
  125. }
  126. k := kDef["keys"]
  127. switch v := k.(type) {
  128. case string:
  129. err := ssh.AddAuthorizedKey(user, v)
  130. if err != nil {
  131. l.WithError(err).WithField("sshKeyConfig", rk).WithField("sshKey", v).Warn("Failed to authorize key")
  132. continue
  133. }
  134. case []interface{}:
  135. for _, subK := range v {
  136. sk, ok := subK.(string)
  137. if !ok {
  138. l.WithField("sshKeyConfig", rk).WithField("sshKey", subK).Warn("Did not understand ssh key")
  139. continue
  140. }
  141. err := ssh.AddAuthorizedKey(user, sk)
  142. if err != nil {
  143. l.WithError(err).WithField("sshKeyConfig", sk).Warn("Failed to authorize key")
  144. continue
  145. }
  146. }
  147. default:
  148. l.WithField("sshKeyConfig", rk).Warn("Authorized user is missing the keys field or was not understood")
  149. }
  150. }
  151. } else {
  152. l.Info("no ssh users to authorize")
  153. }
  154. var runner func()
  155. if c.GetBool("sshd.enabled", false) {
  156. ssh.Stop()
  157. runner = func() {
  158. if err := ssh.Run(listen); err != nil {
  159. l.WithField("err", err).Warn("Failed to run the SSH server")
  160. }
  161. }
  162. } else {
  163. ssh.Stop()
  164. }
  165. return runner, nil
  166. }
  167. func attachCommands(l *logrus.Logger, c *config.C, ssh *sshd.SSHServer, f *Interface) {
  168. ssh.RegisterCommand(&sshd.Command{
  169. Name: "list-hostmap",
  170. ShortDescription: "List all known previously connected hosts",
  171. Flags: func() (*flag.FlagSet, interface{}) {
  172. fl := flag.NewFlagSet("", flag.ContinueOnError)
  173. s := sshListHostMapFlags{}
  174. fl.BoolVar(&s.Json, "json", false, "outputs as json with more information")
  175. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  176. fl.BoolVar(&s.ByIndex, "by-index", false, "gets all hosts in the hostmap from the index table")
  177. return fl, &s
  178. },
  179. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  180. return sshListHostMap(f.hostMap, fs, w)
  181. },
  182. })
  183. ssh.RegisterCommand(&sshd.Command{
  184. Name: "list-pending-hostmap",
  185. ShortDescription: "List all handshaking hosts",
  186. Flags: func() (*flag.FlagSet, interface{}) {
  187. fl := flag.NewFlagSet("", flag.ContinueOnError)
  188. s := sshListHostMapFlags{}
  189. fl.BoolVar(&s.Json, "json", false, "outputs as json with more information")
  190. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  191. fl.BoolVar(&s.ByIndex, "by-index", false, "gets all hosts in the hostmap from the index table")
  192. return fl, &s
  193. },
  194. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  195. return sshListHostMap(f.handshakeManager, fs, w)
  196. },
  197. })
  198. ssh.RegisterCommand(&sshd.Command{
  199. Name: "list-lighthouse-addrmap",
  200. ShortDescription: "List all lighthouse map entries",
  201. Flags: func() (*flag.FlagSet, interface{}) {
  202. fl := flag.NewFlagSet("", flag.ContinueOnError)
  203. s := sshListHostMapFlags{}
  204. fl.BoolVar(&s.Json, "json", false, "outputs as json with more information")
  205. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  206. return fl, &s
  207. },
  208. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  209. return sshListLighthouseMap(f.lightHouse, fs, w)
  210. },
  211. })
  212. ssh.RegisterCommand(&sshd.Command{
  213. Name: "reload",
  214. ShortDescription: "Reloads configuration from disk, same as sending HUP to the process",
  215. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  216. return sshReload(c, w)
  217. },
  218. })
  219. ssh.RegisterCommand(&sshd.Command{
  220. Name: "start-cpu-profile",
  221. ShortDescription: "Starts a cpu profile and write output to the provided file, ex: `cpu-profile.pb.gz`",
  222. Callback: sshStartCpuProfile,
  223. })
  224. ssh.RegisterCommand(&sshd.Command{
  225. Name: "stop-cpu-profile",
  226. ShortDescription: "Stops a cpu profile and writes output to the previously provided file",
  227. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  228. pprof.StopCPUProfile()
  229. return w.WriteLine("If a CPU profile was running it is now stopped")
  230. },
  231. })
  232. ssh.RegisterCommand(&sshd.Command{
  233. Name: "save-heap-profile",
  234. ShortDescription: "Saves a heap profile to the provided path, ex: `heap-profile.pb.gz`",
  235. Callback: sshGetHeapProfile,
  236. })
  237. ssh.RegisterCommand(&sshd.Command{
  238. Name: "mutex-profile-fraction",
  239. ShortDescription: "Gets or sets runtime.SetMutexProfileFraction",
  240. Callback: sshMutexProfileFraction,
  241. })
  242. ssh.RegisterCommand(&sshd.Command{
  243. Name: "save-mutex-profile",
  244. ShortDescription: "Saves a mutex profile to the provided path, ex: `mutex-profile.pb.gz`",
  245. Callback: sshGetMutexProfile,
  246. })
  247. ssh.RegisterCommand(&sshd.Command{
  248. Name: "log-level",
  249. ShortDescription: "Gets or sets the current log level",
  250. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  251. return sshLogLevel(l, fs, a, w)
  252. },
  253. })
  254. ssh.RegisterCommand(&sshd.Command{
  255. Name: "log-format",
  256. ShortDescription: "Gets or sets the current log format",
  257. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  258. return sshLogFormat(l, fs, a, w)
  259. },
  260. })
  261. ssh.RegisterCommand(&sshd.Command{
  262. Name: "version",
  263. ShortDescription: "Prints the currently running version of nebula",
  264. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  265. return sshVersion(f, fs, a, w)
  266. },
  267. })
  268. ssh.RegisterCommand(&sshd.Command{
  269. Name: "device-info",
  270. ShortDescription: "Prints information about the network device.",
  271. Flags: func() (*flag.FlagSet, interface{}) {
  272. fl := flag.NewFlagSet("", flag.ContinueOnError)
  273. s := sshDeviceInfoFlags{}
  274. fl.BoolVar(&s.Json, "json", false, "outputs as json with more information")
  275. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  276. return fl, &s
  277. },
  278. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  279. return sshDeviceInfo(f, fs, w)
  280. },
  281. })
  282. ssh.RegisterCommand(&sshd.Command{
  283. Name: "print-cert",
  284. ShortDescription: "Prints the current certificate being used or the certificate for the provided vpn ip",
  285. Flags: func() (*flag.FlagSet, interface{}) {
  286. fl := flag.NewFlagSet("", flag.ContinueOnError)
  287. s := sshPrintCertFlags{}
  288. fl.BoolVar(&s.Json, "json", false, "outputs as json")
  289. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  290. fl.BoolVar(&s.Raw, "raw", false, "raw prints the PEM encoded certificate, not compatible with -json or -pretty")
  291. return fl, &s
  292. },
  293. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  294. return sshPrintCert(f, fs, a, w)
  295. },
  296. })
  297. ssh.RegisterCommand(&sshd.Command{
  298. Name: "print-tunnel",
  299. ShortDescription: "Prints json details about a tunnel for the provided vpn ip",
  300. Flags: func() (*flag.FlagSet, interface{}) {
  301. fl := flag.NewFlagSet("", flag.ContinueOnError)
  302. s := sshPrintTunnelFlags{}
  303. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json")
  304. return fl, &s
  305. },
  306. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  307. return sshPrintTunnel(f, fs, a, w)
  308. },
  309. })
  310. ssh.RegisterCommand(&sshd.Command{
  311. Name: "print-relays",
  312. ShortDescription: "Prints json details about all relay info",
  313. Flags: func() (*flag.FlagSet, interface{}) {
  314. fl := flag.NewFlagSet("", flag.ContinueOnError)
  315. s := sshPrintTunnelFlags{}
  316. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json")
  317. return fl, &s
  318. },
  319. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  320. return sshPrintRelays(f, fs, a, w)
  321. },
  322. })
  323. ssh.RegisterCommand(&sshd.Command{
  324. Name: "change-remote",
  325. ShortDescription: "Changes the remote address used in the tunnel for the provided vpn ip",
  326. Flags: func() (*flag.FlagSet, interface{}) {
  327. fl := flag.NewFlagSet("", flag.ContinueOnError)
  328. s := sshChangeRemoteFlags{}
  329. fl.StringVar(&s.Address, "address", "", "The new remote address, ip:port")
  330. return fl, &s
  331. },
  332. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  333. return sshChangeRemote(f, fs, a, w)
  334. },
  335. })
  336. ssh.RegisterCommand(&sshd.Command{
  337. Name: "close-tunnel",
  338. ShortDescription: "Closes a tunnel for the provided vpn ip",
  339. Flags: func() (*flag.FlagSet, interface{}) {
  340. fl := flag.NewFlagSet("", flag.ContinueOnError)
  341. s := sshCloseTunnelFlags{}
  342. fl.BoolVar(&s.LocalOnly, "local-only", false, "Disables notifying the remote that the tunnel is shutting down")
  343. return fl, &s
  344. },
  345. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  346. return sshCloseTunnel(f, fs, a, w)
  347. },
  348. })
  349. ssh.RegisterCommand(&sshd.Command{
  350. Name: "create-tunnel",
  351. ShortDescription: "Creates a tunnel for the provided vpn ip and address",
  352. Help: "The lighthouses will be queried for real addresses but you can provide one as well.",
  353. Flags: func() (*flag.FlagSet, interface{}) {
  354. fl := flag.NewFlagSet("", flag.ContinueOnError)
  355. s := sshCreateTunnelFlags{}
  356. fl.StringVar(&s.Address, "address", "", "Optionally provide a real remote address, ip:port ")
  357. return fl, &s
  358. },
  359. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  360. return sshCreateTunnel(f, fs, a, w)
  361. },
  362. })
  363. ssh.RegisterCommand(&sshd.Command{
  364. Name: "query-lighthouse",
  365. ShortDescription: "Query the lighthouses for the provided vpn ip",
  366. Help: "This command is asynchronous. Only currently known udp ips will be printed.",
  367. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  368. return sshQueryLighthouse(f, fs, a, w)
  369. },
  370. })
  371. }
  372. func sshListHostMap(hl controlHostLister, a interface{}, w sshd.StringWriter) error {
  373. fs, ok := a.(*sshListHostMapFlags)
  374. if !ok {
  375. //TODO: error
  376. return nil
  377. }
  378. var hm []ControlHostInfo
  379. if fs.ByIndex {
  380. hm = listHostMapIndexes(hl)
  381. } else {
  382. hm = listHostMapHosts(hl)
  383. }
  384. sort.Slice(hm, func(i, j int) bool {
  385. return bytes.Compare(hm[i].VpnIp, hm[j].VpnIp) < 0
  386. })
  387. if fs.Json || fs.Pretty {
  388. js := json.NewEncoder(w.GetWriter())
  389. if fs.Pretty {
  390. js.SetIndent("", " ")
  391. }
  392. err := js.Encode(hm)
  393. if err != nil {
  394. //TODO
  395. return nil
  396. }
  397. } else {
  398. for _, v := range hm {
  399. err := w.WriteLine(fmt.Sprintf("%s: %s", v.VpnIp, v.RemoteAddrs))
  400. if err != nil {
  401. return err
  402. }
  403. }
  404. }
  405. return nil
  406. }
  407. func sshListLighthouseMap(lightHouse *LightHouse, a interface{}, w sshd.StringWriter) error {
  408. fs, ok := a.(*sshListHostMapFlags)
  409. if !ok {
  410. //TODO: error
  411. return nil
  412. }
  413. type lighthouseInfo struct {
  414. VpnIp string `json:"vpnIp"`
  415. Addrs *CacheMap `json:"addrs"`
  416. }
  417. lightHouse.RLock()
  418. addrMap := make([]lighthouseInfo, len(lightHouse.addrMap))
  419. x := 0
  420. for k, v := range lightHouse.addrMap {
  421. addrMap[x] = lighthouseInfo{
  422. VpnIp: k.String(),
  423. Addrs: v.CopyCache(),
  424. }
  425. x++
  426. }
  427. lightHouse.RUnlock()
  428. sort.Slice(addrMap, func(i, j int) bool {
  429. return strings.Compare(addrMap[i].VpnIp, addrMap[j].VpnIp) < 0
  430. })
  431. if fs.Json || fs.Pretty {
  432. js := json.NewEncoder(w.GetWriter())
  433. if fs.Pretty {
  434. js.SetIndent("", " ")
  435. }
  436. err := js.Encode(addrMap)
  437. if err != nil {
  438. //TODO
  439. return nil
  440. }
  441. } else {
  442. for _, v := range addrMap {
  443. b, err := json.Marshal(v.Addrs)
  444. if err != nil {
  445. return err
  446. }
  447. err = w.WriteLine(fmt.Sprintf("%s: %s", v.VpnIp, string(b)))
  448. if err != nil {
  449. return err
  450. }
  451. }
  452. }
  453. return nil
  454. }
  455. func sshStartCpuProfile(fs interface{}, a []string, w sshd.StringWriter) error {
  456. if len(a) == 0 {
  457. err := w.WriteLine("No path to write profile provided")
  458. return err
  459. }
  460. file, err := os.Create(a[0])
  461. if err != nil {
  462. err = w.WriteLine(fmt.Sprintf("Unable to create profile file: %s", err))
  463. return err
  464. }
  465. err = pprof.StartCPUProfile(file)
  466. if err != nil {
  467. err = w.WriteLine(fmt.Sprintf("Unable to start cpu profile: %s", err))
  468. return err
  469. }
  470. err = w.WriteLine(fmt.Sprintf("Started cpu profile, issue stop-cpu-profile to write the output to %s", a))
  471. return err
  472. }
  473. func sshVersion(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  474. return w.WriteLine(fmt.Sprintf("%s", ifce.version))
  475. }
  476. func sshQueryLighthouse(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  477. if len(a) == 0 {
  478. return w.WriteLine("No vpn ip was provided")
  479. }
  480. parsedIp := net.ParseIP(a[0])
  481. if parsedIp == nil {
  482. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  483. }
  484. vpnIp := iputil.Ip2VpnIp(parsedIp)
  485. if vpnIp == 0 {
  486. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  487. }
  488. var cm *CacheMap
  489. rl := ifce.lightHouse.Query(vpnIp)
  490. if rl != nil {
  491. cm = rl.CopyCache()
  492. }
  493. return json.NewEncoder(w.GetWriter()).Encode(cm)
  494. }
  495. func sshCloseTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  496. flags, ok := fs.(*sshCloseTunnelFlags)
  497. if !ok {
  498. //TODO: error
  499. return nil
  500. }
  501. if len(a) == 0 {
  502. return w.WriteLine("No vpn ip was provided")
  503. }
  504. parsedIp := net.ParseIP(a[0])
  505. if parsedIp == nil {
  506. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  507. }
  508. vpnIp := iputil.Ip2VpnIp(parsedIp)
  509. if vpnIp == 0 {
  510. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  511. }
  512. hostInfo := ifce.hostMap.QueryVpnIp(vpnIp)
  513. if hostInfo == nil {
  514. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  515. }
  516. if !flags.LocalOnly {
  517. ifce.send(
  518. header.CloseTunnel,
  519. 0,
  520. hostInfo.ConnectionState,
  521. hostInfo,
  522. []byte{},
  523. make([]byte, 12, 12),
  524. make([]byte, mtu),
  525. )
  526. }
  527. ifce.closeTunnel(hostInfo)
  528. return w.WriteLine("Closed")
  529. }
  530. func sshCreateTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  531. flags, ok := fs.(*sshCreateTunnelFlags)
  532. if !ok {
  533. //TODO: error
  534. return nil
  535. }
  536. if len(a) == 0 {
  537. return w.WriteLine("No vpn ip was provided")
  538. }
  539. parsedIp := net.ParseIP(a[0])
  540. if parsedIp == nil {
  541. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  542. }
  543. vpnIp := iputil.Ip2VpnIp(parsedIp)
  544. if vpnIp == 0 {
  545. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  546. }
  547. hostInfo := ifce.hostMap.QueryVpnIp(vpnIp)
  548. if hostInfo != nil {
  549. return w.WriteLine(fmt.Sprintf("Tunnel already exists"))
  550. }
  551. hostInfo = ifce.handshakeManager.QueryVpnIp(vpnIp)
  552. if hostInfo != nil {
  553. return w.WriteLine(fmt.Sprintf("Tunnel already handshaking"))
  554. }
  555. var addr *udp.Addr
  556. if flags.Address != "" {
  557. addr = udp.NewAddrFromString(flags.Address)
  558. if addr == nil {
  559. return w.WriteLine("Address could not be parsed")
  560. }
  561. }
  562. hostInfo = ifce.handshakeManager.StartHandshake(vpnIp, nil)
  563. if addr != nil {
  564. hostInfo.SetRemote(addr)
  565. }
  566. return w.WriteLine("Created")
  567. }
  568. func sshChangeRemote(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  569. flags, ok := fs.(*sshChangeRemoteFlags)
  570. if !ok {
  571. //TODO: error
  572. return nil
  573. }
  574. if len(a) == 0 {
  575. return w.WriteLine("No vpn ip was provided")
  576. }
  577. if flags.Address == "" {
  578. return w.WriteLine("No address was provided")
  579. }
  580. addr := udp.NewAddrFromString(flags.Address)
  581. if addr == nil {
  582. return w.WriteLine("Address could not be parsed")
  583. }
  584. parsedIp := net.ParseIP(a[0])
  585. if parsedIp == nil {
  586. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  587. }
  588. vpnIp := iputil.Ip2VpnIp(parsedIp)
  589. if vpnIp == 0 {
  590. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  591. }
  592. hostInfo := ifce.hostMap.QueryVpnIp(vpnIp)
  593. if hostInfo == nil {
  594. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  595. }
  596. hostInfo.SetRemote(addr)
  597. return w.WriteLine("Changed")
  598. }
  599. func sshGetHeapProfile(fs interface{}, a []string, w sshd.StringWriter) error {
  600. if len(a) == 0 {
  601. return w.WriteLine("No path to write profile provided")
  602. }
  603. file, err := os.Create(a[0])
  604. if err != nil {
  605. err = w.WriteLine(fmt.Sprintf("Unable to create profile file: %s", err))
  606. return err
  607. }
  608. err = pprof.WriteHeapProfile(file)
  609. if err != nil {
  610. err = w.WriteLine(fmt.Sprintf("Unable to write profile: %s", err))
  611. return err
  612. }
  613. err = w.WriteLine(fmt.Sprintf("Mem profile created at %s", a))
  614. return err
  615. }
  616. func sshMutexProfileFraction(fs interface{}, a []string, w sshd.StringWriter) error {
  617. if len(a) == 0 {
  618. rate := runtime.SetMutexProfileFraction(-1)
  619. return w.WriteLine(fmt.Sprintf("Current value: %d", rate))
  620. }
  621. newRate, err := strconv.Atoi(a[0])
  622. if err != nil {
  623. return w.WriteLine(fmt.Sprintf("Invalid argument: %s", a[0]))
  624. }
  625. oldRate := runtime.SetMutexProfileFraction(newRate)
  626. return w.WriteLine(fmt.Sprintf("New value: %d. Old value: %d", newRate, oldRate))
  627. }
  628. func sshGetMutexProfile(fs interface{}, a []string, w sshd.StringWriter) error {
  629. if len(a) == 0 {
  630. return w.WriteLine("No path to write profile provided")
  631. }
  632. file, err := os.Create(a[0])
  633. if err != nil {
  634. return w.WriteLine(fmt.Sprintf("Unable to create profile file: %s", err))
  635. }
  636. defer file.Close()
  637. mutexProfile := pprof.Lookup("mutex")
  638. if mutexProfile == nil {
  639. return w.WriteLine("Unable to get pprof.Lookup(\"mutex\")")
  640. }
  641. err = mutexProfile.WriteTo(file, 0)
  642. if err != nil {
  643. return w.WriteLine(fmt.Sprintf("Unable to write profile: %s", err))
  644. }
  645. return w.WriteLine(fmt.Sprintf("Mutex profile created at %s", a))
  646. }
  647. func sshLogLevel(l *logrus.Logger, fs interface{}, a []string, w sshd.StringWriter) error {
  648. if len(a) == 0 {
  649. return w.WriteLine(fmt.Sprintf("Log level is: %s", l.Level))
  650. }
  651. level, err := logrus.ParseLevel(a[0])
  652. if err != nil {
  653. return w.WriteLine(fmt.Sprintf("Unknown log level %s. Possible log levels: %s", a, logrus.AllLevels))
  654. }
  655. l.SetLevel(level)
  656. return w.WriteLine(fmt.Sprintf("Log level is: %s", l.Level))
  657. }
  658. func sshLogFormat(l *logrus.Logger, fs interface{}, a []string, w sshd.StringWriter) error {
  659. if len(a) == 0 {
  660. return w.WriteLine(fmt.Sprintf("Log format is: %s", reflect.TypeOf(l.Formatter)))
  661. }
  662. logFormat := strings.ToLower(a[0])
  663. switch logFormat {
  664. case "text":
  665. l.Formatter = &logrus.TextFormatter{}
  666. case "json":
  667. l.Formatter = &logrus.JSONFormatter{}
  668. default:
  669. return fmt.Errorf("unknown log format `%s`. possible formats: %s", logFormat, []string{"text", "json"})
  670. }
  671. return w.WriteLine(fmt.Sprintf("Log format is: %s", reflect.TypeOf(l.Formatter)))
  672. }
  673. func sshPrintCert(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  674. args, ok := fs.(*sshPrintCertFlags)
  675. if !ok {
  676. //TODO: error
  677. return nil
  678. }
  679. cert := ifce.pki.GetCertState().Certificate
  680. if len(a) > 0 {
  681. parsedIp := net.ParseIP(a[0])
  682. if parsedIp == nil {
  683. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  684. }
  685. vpnIp := iputil.Ip2VpnIp(parsedIp)
  686. if vpnIp == 0 {
  687. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  688. }
  689. hostInfo := ifce.hostMap.QueryVpnIp(vpnIp)
  690. if hostInfo == nil {
  691. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  692. }
  693. cert = hostInfo.GetCert()
  694. }
  695. if args.Json || args.Pretty {
  696. b, err := cert.MarshalJSON()
  697. if err != nil {
  698. //TODO: handle it
  699. return nil
  700. }
  701. if args.Pretty {
  702. buf := new(bytes.Buffer)
  703. err := json.Indent(buf, b, "", " ")
  704. b = buf.Bytes()
  705. if err != nil {
  706. //TODO: handle it
  707. return nil
  708. }
  709. }
  710. return w.WriteBytes(b)
  711. }
  712. if args.Raw {
  713. b, err := cert.MarshalToPEM()
  714. if err != nil {
  715. //TODO: handle it
  716. return nil
  717. }
  718. return w.WriteBytes(b)
  719. }
  720. return w.WriteLine(cert.String())
  721. }
  722. func sshPrintRelays(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  723. args, ok := fs.(*sshPrintTunnelFlags)
  724. if !ok {
  725. //TODO: error
  726. w.WriteLine(fmt.Sprintf("sshPrintRelays failed to convert args type"))
  727. return nil
  728. }
  729. relays := map[uint32]*HostInfo{}
  730. ifce.hostMap.Lock()
  731. for k, v := range ifce.hostMap.Relays {
  732. relays[k] = v
  733. }
  734. ifce.hostMap.Unlock()
  735. type RelayFor struct {
  736. Error error
  737. Type string
  738. State string
  739. PeerIp iputil.VpnIp
  740. LocalIndex uint32
  741. RemoteIndex uint32
  742. RelayedThrough []iputil.VpnIp
  743. }
  744. type RelayOutput struct {
  745. NebulaIp iputil.VpnIp
  746. RelayForIps []RelayFor
  747. }
  748. type CmdOutput struct {
  749. Relays []*RelayOutput
  750. }
  751. co := CmdOutput{}
  752. enc := json.NewEncoder(w.GetWriter())
  753. if args.Pretty {
  754. enc.SetIndent("", " ")
  755. }
  756. for k, v := range relays {
  757. ro := RelayOutput{NebulaIp: v.vpnIp}
  758. co.Relays = append(co.Relays, &ro)
  759. relayHI := ifce.hostMap.QueryVpnIp(v.vpnIp)
  760. if relayHI == nil {
  761. ro.RelayForIps = append(ro.RelayForIps, RelayFor{Error: errors.New("could not find hostinfo")})
  762. continue
  763. }
  764. for _, vpnIp := range relayHI.relayState.CopyRelayForIps() {
  765. rf := RelayFor{Error: nil}
  766. r, ok := relayHI.relayState.GetRelayForByIp(vpnIp)
  767. if ok {
  768. t := ""
  769. switch r.Type {
  770. case ForwardingType:
  771. t = "forwarding"
  772. case TerminalType:
  773. t = "terminal"
  774. default:
  775. t = "unknown"
  776. }
  777. s := ""
  778. switch r.State {
  779. case Requested:
  780. s = "requested"
  781. case Established:
  782. s = "established"
  783. default:
  784. s = "unknown"
  785. }
  786. rf.LocalIndex = r.LocalIndex
  787. rf.RemoteIndex = r.RemoteIndex
  788. rf.PeerIp = r.PeerIp
  789. rf.Type = t
  790. rf.State = s
  791. if rf.LocalIndex != k {
  792. rf.Error = fmt.Errorf("hostmap LocalIndex '%v' does not match RelayState LocalIndex", k)
  793. }
  794. }
  795. relayedHI := ifce.hostMap.QueryVpnIp(vpnIp)
  796. if relayedHI != nil {
  797. rf.RelayedThrough = append(rf.RelayedThrough, relayedHI.relayState.CopyRelayIps()...)
  798. }
  799. ro.RelayForIps = append(ro.RelayForIps, rf)
  800. }
  801. }
  802. err := enc.Encode(co)
  803. if err != nil {
  804. return err
  805. }
  806. return nil
  807. }
  808. func sshPrintTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  809. args, ok := fs.(*sshPrintTunnelFlags)
  810. if !ok {
  811. //TODO: error
  812. return nil
  813. }
  814. if len(a) == 0 {
  815. return w.WriteLine("No vpn ip was provided")
  816. }
  817. parsedIp := net.ParseIP(a[0])
  818. if parsedIp == nil {
  819. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  820. }
  821. vpnIp := iputil.Ip2VpnIp(parsedIp)
  822. if vpnIp == 0 {
  823. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  824. }
  825. hostInfo := ifce.hostMap.QueryVpnIp(vpnIp)
  826. if hostInfo == nil {
  827. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  828. }
  829. enc := json.NewEncoder(w.GetWriter())
  830. if args.Pretty {
  831. enc.SetIndent("", " ")
  832. }
  833. return enc.Encode(copyHostInfo(hostInfo, ifce.hostMap.GetPreferredRanges()))
  834. }
  835. func sshDeviceInfo(ifce *Interface, fs interface{}, w sshd.StringWriter) error {
  836. data := struct {
  837. Name string `json:"name"`
  838. Cidr string `json:"cidr"`
  839. }{
  840. Name: ifce.inside.Name(),
  841. Cidr: ifce.inside.Cidr().String(),
  842. }
  843. flags, ok := fs.(*sshDeviceInfoFlags)
  844. if !ok {
  845. return fmt.Errorf("internal error: expected flags to be sshDeviceInfoFlags but was %+v", fs)
  846. }
  847. if flags.Json || flags.Pretty {
  848. js := json.NewEncoder(w.GetWriter())
  849. if flags.Pretty {
  850. js.SetIndent("", " ")
  851. }
  852. return js.Encode(data)
  853. } else {
  854. return w.WriteLine(fmt.Sprintf("name=%v cidr=%v", data.Name, data.Cidr))
  855. }
  856. }
  857. func sshReload(c *config.C, w sshd.StringWriter) error {
  858. err := w.WriteLine("Reloading config")
  859. c.ReloadConfig()
  860. return err
  861. }