ssh.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. package nebula
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "flag"
  6. "fmt"
  7. "io/ioutil"
  8. "net"
  9. "os"
  10. "reflect"
  11. "runtime/pprof"
  12. "sort"
  13. "strings"
  14. "syscall"
  15. "github.com/sirupsen/logrus"
  16. "github.com/slackhq/nebula/sshd"
  17. )
  18. type sshListHostMapFlags struct {
  19. Json bool
  20. Pretty bool
  21. }
  22. type sshPrintCertFlags struct {
  23. Json bool
  24. Pretty bool
  25. Raw bool
  26. }
  27. type sshPrintTunnelFlags struct {
  28. Pretty bool
  29. }
  30. type sshChangeRemoteFlags struct {
  31. Address string
  32. }
  33. type sshCloseTunnelFlags struct {
  34. LocalOnly bool
  35. }
  36. type sshCreateTunnelFlags struct {
  37. Address string
  38. }
  39. func wireSSHReload(l *logrus.Logger, ssh *sshd.SSHServer, c *Config) {
  40. c.RegisterReloadCallback(func(c *Config) {
  41. if c.GetBool("sshd.enabled", false) {
  42. sshRun, err := configSSH(l, ssh, c)
  43. if err != nil {
  44. l.WithError(err).Error("Failed to reconfigure the sshd")
  45. ssh.Stop()
  46. }
  47. if sshRun != nil {
  48. go sshRun()
  49. }
  50. } else {
  51. ssh.Stop()
  52. }
  53. })
  54. }
  55. // configSSH reads the ssh info out of the passed-in Config and
  56. // updates the passed-in SSHServer. On success, it returns a function
  57. // that callers may invoke to run the configured ssh server. On
  58. // failure, it returns nil, error.
  59. func configSSH(l *logrus.Logger, ssh *sshd.SSHServer, c *Config) (func(), error) {
  60. //TODO conntrack list
  61. //TODO print firewall rules or hash?
  62. listen := c.GetString("sshd.listen", "")
  63. if listen == "" {
  64. return nil, fmt.Errorf("sshd.listen must be provided")
  65. }
  66. _, port, err := net.SplitHostPort(listen)
  67. if err != nil {
  68. return nil, fmt.Errorf("invalid sshd.listen address: %s", err)
  69. }
  70. if port == "22" {
  71. return nil, fmt.Errorf("sshd.listen can not use port 22")
  72. }
  73. //TODO: no good way to reload this right now
  74. hostKeyFile := c.GetString("sshd.host_key", "")
  75. if hostKeyFile == "" {
  76. return nil, fmt.Errorf("sshd.host_key must be provided")
  77. }
  78. hostKeyBytes, err := ioutil.ReadFile(hostKeyFile)
  79. if err != nil {
  80. return nil, fmt.Errorf("error while loading sshd.host_key file: %s", err)
  81. }
  82. err = ssh.SetHostKey(hostKeyBytes)
  83. if err != nil {
  84. return nil, fmt.Errorf("error while adding sshd.host_key: %s", err)
  85. }
  86. rawKeys := c.Get("sshd.authorized_users")
  87. keys, ok := rawKeys.([]interface{})
  88. if ok {
  89. for _, rk := range keys {
  90. kDef, ok := rk.(map[interface{}]interface{})
  91. if !ok {
  92. l.WithField("sshKeyConfig", rk).Warn("Authorized user had an error, ignoring")
  93. continue
  94. }
  95. user, ok := kDef["user"].(string)
  96. if !ok {
  97. l.WithField("sshKeyConfig", rk).Warn("Authorized user is missing the user field")
  98. continue
  99. }
  100. k := kDef["keys"]
  101. switch v := k.(type) {
  102. case string:
  103. err := ssh.AddAuthorizedKey(user, v)
  104. if err != nil {
  105. l.WithError(err).WithField("sshKeyConfig", rk).WithField("sshKey", v).Warn("Failed to authorize key")
  106. continue
  107. }
  108. case []interface{}:
  109. for _, subK := range v {
  110. sk, ok := subK.(string)
  111. if !ok {
  112. l.WithField("sshKeyConfig", rk).WithField("sshKey", subK).Warn("Did not understand ssh key")
  113. continue
  114. }
  115. err := ssh.AddAuthorizedKey(user, sk)
  116. if err != nil {
  117. l.WithError(err).WithField("sshKeyConfig", sk).Warn("Failed to authorize key")
  118. continue
  119. }
  120. }
  121. default:
  122. l.WithField("sshKeyConfig", rk).Warn("Authorized user is missing the keys field or was not understood")
  123. }
  124. }
  125. } else {
  126. l.Info("no ssh users to authorize")
  127. }
  128. var runner func()
  129. if c.GetBool("sshd.enabled", false) {
  130. ssh.Stop()
  131. runner = func() {
  132. if err := ssh.Run(listen); err != nil {
  133. l.WithField("err", err).Warn("Failed to run the SSH server")
  134. }
  135. }
  136. } else {
  137. ssh.Stop()
  138. }
  139. return runner, nil
  140. }
  141. func attachCommands(l *logrus.Logger, ssh *sshd.SSHServer, hostMap *HostMap, pendingHostMap *HostMap, lightHouse *LightHouse, ifce *Interface) {
  142. ssh.RegisterCommand(&sshd.Command{
  143. Name: "list-hostmap",
  144. ShortDescription: "List all known previously connected hosts",
  145. Flags: func() (*flag.FlagSet, interface{}) {
  146. fl := flag.NewFlagSet("", flag.ContinueOnError)
  147. s := sshListHostMapFlags{}
  148. fl.BoolVar(&s.Json, "json", false, "outputs as json with more information")
  149. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  150. return fl, &s
  151. },
  152. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  153. return sshListHostMap(hostMap, fs, w)
  154. },
  155. })
  156. ssh.RegisterCommand(&sshd.Command{
  157. Name: "list-pending-hostmap",
  158. ShortDescription: "List all handshaking hosts",
  159. Flags: func() (*flag.FlagSet, interface{}) {
  160. fl := flag.NewFlagSet("", flag.ContinueOnError)
  161. s := sshListHostMapFlags{}
  162. fl.BoolVar(&s.Json, "json", false, "outputs as json with more information")
  163. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  164. return fl, &s
  165. },
  166. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  167. return sshListHostMap(pendingHostMap, fs, w)
  168. },
  169. })
  170. ssh.RegisterCommand(&sshd.Command{
  171. Name: "list-lighthouse-addrmap",
  172. ShortDescription: "List all lighthouse map entries",
  173. Flags: func() (*flag.FlagSet, interface{}) {
  174. fl := flag.NewFlagSet("", flag.ContinueOnError)
  175. s := sshListHostMapFlags{}
  176. fl.BoolVar(&s.Json, "json", false, "outputs as json with more information")
  177. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  178. return fl, &s
  179. },
  180. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  181. return sshListLighthouseMap(lightHouse, fs, w)
  182. },
  183. })
  184. ssh.RegisterCommand(&sshd.Command{
  185. Name: "reload",
  186. ShortDescription: "Reloads configuration from disk, same as sending HUP to the process",
  187. Callback: sshReload,
  188. })
  189. ssh.RegisterCommand(&sshd.Command{
  190. Name: "start-cpu-profile",
  191. ShortDescription: "Starts a cpu profile and write output to the provided file",
  192. Callback: sshStartCpuProfile,
  193. })
  194. ssh.RegisterCommand(&sshd.Command{
  195. Name: "stop-cpu-profile",
  196. ShortDescription: "Stops a cpu profile and writes output to the previously provided file",
  197. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  198. pprof.StopCPUProfile()
  199. return w.WriteLine("If a CPU profile was running it is now stopped")
  200. },
  201. })
  202. ssh.RegisterCommand(&sshd.Command{
  203. Name: "save-heap-profile",
  204. ShortDescription: "Saves a heap profile to the provided path",
  205. Callback: sshGetHeapProfile,
  206. })
  207. ssh.RegisterCommand(&sshd.Command{
  208. Name: "log-level",
  209. ShortDescription: "Gets or sets the current log level",
  210. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  211. return sshLogLevel(l, fs, a, w)
  212. },
  213. })
  214. ssh.RegisterCommand(&sshd.Command{
  215. Name: "log-format",
  216. ShortDescription: "Gets or sets the current log format",
  217. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  218. return sshLogFormat(l, fs, a, w)
  219. },
  220. })
  221. ssh.RegisterCommand(&sshd.Command{
  222. Name: "version",
  223. ShortDescription: "Prints the currently running version of nebula",
  224. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  225. return sshVersion(ifce, fs, a, w)
  226. },
  227. })
  228. ssh.RegisterCommand(&sshd.Command{
  229. Name: "print-cert",
  230. ShortDescription: "Prints the current certificate being used or the certificate for the provided vpn ip",
  231. Flags: func() (*flag.FlagSet, interface{}) {
  232. fl := flag.NewFlagSet("", flag.ContinueOnError)
  233. s := sshPrintCertFlags{}
  234. fl.BoolVar(&s.Json, "json", false, "outputs as json")
  235. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json, assumes -json")
  236. fl.BoolVar(&s.Raw, "raw", false, "raw prints the PEM encoded certificate, not compatible with -json or -pretty")
  237. return fl, &s
  238. },
  239. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  240. return sshPrintCert(ifce, fs, a, w)
  241. },
  242. })
  243. ssh.RegisterCommand(&sshd.Command{
  244. Name: "print-tunnel",
  245. ShortDescription: "Prints json details about a tunnel for the provided vpn ip",
  246. Flags: func() (*flag.FlagSet, interface{}) {
  247. fl := flag.NewFlagSet("", flag.ContinueOnError)
  248. s := sshPrintTunnelFlags{}
  249. fl.BoolVar(&s.Pretty, "pretty", false, "pretty prints json")
  250. return fl, &s
  251. },
  252. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  253. return sshPrintTunnel(ifce, fs, a, w)
  254. },
  255. })
  256. ssh.RegisterCommand(&sshd.Command{
  257. Name: "change-remote",
  258. ShortDescription: "Changes the remote address used in the tunnel for the provided vpn ip",
  259. Flags: func() (*flag.FlagSet, interface{}) {
  260. fl := flag.NewFlagSet("", flag.ContinueOnError)
  261. s := sshChangeRemoteFlags{}
  262. fl.StringVar(&s.Address, "address", "", "The new remote address, ip:port")
  263. return fl, &s
  264. },
  265. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  266. return sshChangeRemote(ifce, fs, a, w)
  267. },
  268. })
  269. ssh.RegisterCommand(&sshd.Command{
  270. Name: "close-tunnel",
  271. ShortDescription: "Closes a tunnel for the provided vpn ip",
  272. Flags: func() (*flag.FlagSet, interface{}) {
  273. fl := flag.NewFlagSet("", flag.ContinueOnError)
  274. s := sshCloseTunnelFlags{}
  275. fl.BoolVar(&s.LocalOnly, "local-only", false, "Disables notifying the remote that the tunnel is shutting down")
  276. return fl, &s
  277. },
  278. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  279. return sshCloseTunnel(ifce, fs, a, w)
  280. },
  281. })
  282. ssh.RegisterCommand(&sshd.Command{
  283. Name: "create-tunnel",
  284. ShortDescription: "Creates a tunnel for the provided vpn ip and address",
  285. Help: "The lighthouses will be queried for real addresses but you can provide one as well.",
  286. Flags: func() (*flag.FlagSet, interface{}) {
  287. fl := flag.NewFlagSet("", flag.ContinueOnError)
  288. s := sshCreateTunnelFlags{}
  289. fl.StringVar(&s.Address, "address", "", "Optionally provide a real remote address, ip:port ")
  290. return fl, &s
  291. },
  292. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  293. return sshCreateTunnel(ifce, fs, a, w)
  294. },
  295. })
  296. ssh.RegisterCommand(&sshd.Command{
  297. Name: "query-lighthouse",
  298. ShortDescription: "Query the lighthouses for the provided vpn ip",
  299. Help: "This command is asynchronous. Only currently known udp ips will be printed.",
  300. Callback: func(fs interface{}, a []string, w sshd.StringWriter) error {
  301. return sshQueryLighthouse(ifce, fs, a, w)
  302. },
  303. })
  304. }
  305. func sshListHostMap(hostMap *HostMap, a interface{}, w sshd.StringWriter) error {
  306. fs, ok := a.(*sshListHostMapFlags)
  307. if !ok {
  308. //TODO: error
  309. return nil
  310. }
  311. hm := listHostMap(hostMap)
  312. sort.Slice(hm, func(i, j int) bool {
  313. return bytes.Compare(hm[i].VpnIP, hm[j].VpnIP) < 0
  314. })
  315. if fs.Json || fs.Pretty {
  316. js := json.NewEncoder(w.GetWriter())
  317. if fs.Pretty {
  318. js.SetIndent("", " ")
  319. }
  320. err := js.Encode(hm)
  321. if err != nil {
  322. //TODO
  323. return nil
  324. }
  325. } else {
  326. for _, v := range hm {
  327. err := w.WriteLine(fmt.Sprintf("%s: %s", v.VpnIP, v.RemoteAddrs))
  328. if err != nil {
  329. return err
  330. }
  331. }
  332. }
  333. return nil
  334. }
  335. func sshListLighthouseMap(lightHouse *LightHouse, a interface{}, w sshd.StringWriter) error {
  336. fs, ok := a.(*sshListHostMapFlags)
  337. if !ok {
  338. //TODO: error
  339. return nil
  340. }
  341. type lighthouseInfo struct {
  342. VpnIP net.IP `json:"vpnIp"`
  343. Addrs *CacheMap `json:"addrs"`
  344. }
  345. lightHouse.RLock()
  346. addrMap := make([]lighthouseInfo, len(lightHouse.addrMap))
  347. x := 0
  348. for k, v := range lightHouse.addrMap {
  349. addrMap[x] = lighthouseInfo{
  350. VpnIP: int2ip(k),
  351. Addrs: v.CopyCache(),
  352. }
  353. x++
  354. }
  355. lightHouse.RUnlock()
  356. sort.Slice(addrMap, func(i, j int) bool {
  357. return bytes.Compare(addrMap[i].VpnIP, addrMap[j].VpnIP) < 0
  358. })
  359. if fs.Json || fs.Pretty {
  360. js := json.NewEncoder(w.GetWriter())
  361. if fs.Pretty {
  362. js.SetIndent("", " ")
  363. }
  364. err := js.Encode(addrMap)
  365. if err != nil {
  366. //TODO
  367. return nil
  368. }
  369. } else {
  370. for _, v := range addrMap {
  371. b, err := json.Marshal(v.Addrs)
  372. if err != nil {
  373. return err
  374. }
  375. err = w.WriteLine(fmt.Sprintf("%s: %s", v.VpnIP, string(b)))
  376. if err != nil {
  377. return err
  378. }
  379. }
  380. }
  381. return nil
  382. }
  383. func sshStartCpuProfile(fs interface{}, a []string, w sshd.StringWriter) error {
  384. if len(a) == 0 {
  385. err := w.WriteLine("No path to write profile provided")
  386. return err
  387. }
  388. file, err := os.Create(a[0])
  389. if err != nil {
  390. err = w.WriteLine(fmt.Sprintf("Unable to create profile file: %s", err))
  391. return err
  392. }
  393. err = pprof.StartCPUProfile(file)
  394. if err != nil {
  395. err = w.WriteLine(fmt.Sprintf("Unable to start cpu profile: %s", err))
  396. return err
  397. }
  398. err = w.WriteLine(fmt.Sprintf("Started cpu profile, issue stop-cpu-profile to write the output to %s", a))
  399. return err
  400. }
  401. func sshVersion(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  402. return w.WriteLine(fmt.Sprintf("%s", ifce.version))
  403. }
  404. func sshQueryLighthouse(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  405. if len(a) == 0 {
  406. return w.WriteLine("No vpn ip was provided")
  407. }
  408. parsedIp := net.ParseIP(a[0])
  409. if parsedIp == nil {
  410. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  411. }
  412. vpnIp := ip2int(parsedIp)
  413. if vpnIp == 0 {
  414. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  415. }
  416. var cm *CacheMap
  417. rl := ifce.lightHouse.Query(vpnIp, ifce)
  418. if rl != nil {
  419. cm = rl.CopyCache()
  420. }
  421. return json.NewEncoder(w.GetWriter()).Encode(cm)
  422. }
  423. func sshCloseTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  424. flags, ok := fs.(*sshCloseTunnelFlags)
  425. if !ok {
  426. //TODO: error
  427. return nil
  428. }
  429. if len(a) == 0 {
  430. return w.WriteLine("No vpn ip was provided")
  431. }
  432. parsedIp := net.ParseIP(a[0])
  433. if parsedIp == nil {
  434. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  435. }
  436. vpnIp := ip2int(parsedIp)
  437. if vpnIp == 0 {
  438. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  439. }
  440. hostInfo, err := ifce.hostMap.QueryVpnIP(uint32(vpnIp))
  441. if err != nil {
  442. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  443. }
  444. if !flags.LocalOnly {
  445. ifce.send(
  446. closeTunnel,
  447. 0,
  448. hostInfo.ConnectionState,
  449. hostInfo,
  450. hostInfo.remote,
  451. []byte{},
  452. make([]byte, 12, 12),
  453. make([]byte, mtu),
  454. )
  455. }
  456. ifce.closeTunnel(hostInfo, false)
  457. return w.WriteLine("Closed")
  458. }
  459. func sshCreateTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  460. flags, ok := fs.(*sshCreateTunnelFlags)
  461. if !ok {
  462. //TODO: error
  463. return nil
  464. }
  465. if len(a) == 0 {
  466. return w.WriteLine("No vpn ip was provided")
  467. }
  468. parsedIp := net.ParseIP(a[0])
  469. if parsedIp == nil {
  470. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  471. }
  472. vpnIp := ip2int(parsedIp)
  473. if vpnIp == 0 {
  474. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  475. }
  476. hostInfo, _ := ifce.hostMap.QueryVpnIP(uint32(vpnIp))
  477. if hostInfo != nil {
  478. return w.WriteLine(fmt.Sprintf("Tunnel already exists"))
  479. }
  480. hostInfo, _ = ifce.handshakeManager.pendingHostMap.QueryVpnIP(uint32(vpnIp))
  481. if hostInfo != nil {
  482. return w.WriteLine(fmt.Sprintf("Tunnel already handshaking"))
  483. }
  484. var addr *udpAddr
  485. if flags.Address != "" {
  486. addr = NewUDPAddrFromString(flags.Address)
  487. if addr == nil {
  488. return w.WriteLine("Address could not be parsed")
  489. }
  490. }
  491. hostInfo = ifce.handshakeManager.AddVpnIP(vpnIp)
  492. if addr != nil {
  493. hostInfo.SetRemote(addr)
  494. }
  495. ifce.getOrHandshake(vpnIp)
  496. return w.WriteLine("Created")
  497. }
  498. func sshChangeRemote(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  499. flags, ok := fs.(*sshChangeRemoteFlags)
  500. if !ok {
  501. //TODO: error
  502. return nil
  503. }
  504. if len(a) == 0 {
  505. return w.WriteLine("No vpn ip was provided")
  506. }
  507. if flags.Address == "" {
  508. return w.WriteLine("No address was provided")
  509. }
  510. addr := NewUDPAddrFromString(flags.Address)
  511. if addr == nil {
  512. return w.WriteLine("Address could not be parsed")
  513. }
  514. parsedIp := net.ParseIP(a[0])
  515. if parsedIp == nil {
  516. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  517. }
  518. vpnIp := ip2int(parsedIp)
  519. if vpnIp == 0 {
  520. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  521. }
  522. hostInfo, err := ifce.hostMap.QueryVpnIP(uint32(vpnIp))
  523. if err != nil {
  524. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  525. }
  526. hostInfo.SetRemote(addr)
  527. return w.WriteLine("Changed")
  528. }
  529. func sshGetHeapProfile(fs interface{}, a []string, w sshd.StringWriter) error {
  530. if len(a) == 0 {
  531. return w.WriteLine("No path to write profile provided")
  532. }
  533. file, err := os.Create(a[0])
  534. if err != nil {
  535. err = w.WriteLine(fmt.Sprintf("Unable to create profile file: %s", err))
  536. return err
  537. }
  538. err = pprof.WriteHeapProfile(file)
  539. if err != nil {
  540. err = w.WriteLine(fmt.Sprintf("Unable to write profile: %s", err))
  541. return err
  542. }
  543. err = w.WriteLine(fmt.Sprintf("Mem profile created at %s", a))
  544. return err
  545. }
  546. func sshLogLevel(l *logrus.Logger, fs interface{}, a []string, w sshd.StringWriter) error {
  547. if len(a) == 0 {
  548. return w.WriteLine(fmt.Sprintf("Log level is: %s", l.Level))
  549. }
  550. level, err := logrus.ParseLevel(a[0])
  551. if err != nil {
  552. return w.WriteLine(fmt.Sprintf("Unknown log level %s. Possible log levels: %s", a, logrus.AllLevels))
  553. }
  554. l.SetLevel(level)
  555. return w.WriteLine(fmt.Sprintf("Log level is: %s", l.Level))
  556. }
  557. func sshLogFormat(l *logrus.Logger, fs interface{}, a []string, w sshd.StringWriter) error {
  558. if len(a) == 0 {
  559. return w.WriteLine(fmt.Sprintf("Log format is: %s", reflect.TypeOf(l.Formatter)))
  560. }
  561. logFormat := strings.ToLower(a[0])
  562. switch logFormat {
  563. case "text":
  564. l.Formatter = &logrus.TextFormatter{}
  565. case "json":
  566. l.Formatter = &logrus.JSONFormatter{}
  567. default:
  568. return fmt.Errorf("unknown log format `%s`. possible formats: %s", logFormat, []string{"text", "json"})
  569. }
  570. return w.WriteLine(fmt.Sprintf("Log format is: %s", reflect.TypeOf(l.Formatter)))
  571. }
  572. func sshPrintCert(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  573. args, ok := fs.(*sshPrintCertFlags)
  574. if !ok {
  575. //TODO: error
  576. return nil
  577. }
  578. cert := ifce.certState.certificate
  579. if len(a) > 0 {
  580. parsedIp := net.ParseIP(a[0])
  581. if parsedIp == nil {
  582. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  583. }
  584. vpnIp := ip2int(parsedIp)
  585. if vpnIp == 0 {
  586. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  587. }
  588. hostInfo, err := ifce.hostMap.QueryVpnIP(uint32(vpnIp))
  589. if err != nil {
  590. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  591. }
  592. cert = hostInfo.GetCert()
  593. }
  594. if args.Json || args.Pretty {
  595. b, err := cert.MarshalJSON()
  596. if err != nil {
  597. //TODO: handle it
  598. return nil
  599. }
  600. if args.Pretty {
  601. buf := new(bytes.Buffer)
  602. err := json.Indent(buf, b, "", " ")
  603. b = buf.Bytes()
  604. if err != nil {
  605. //TODO: handle it
  606. return nil
  607. }
  608. }
  609. return w.WriteBytes(b)
  610. }
  611. if args.Raw {
  612. b, err := cert.MarshalToPEM()
  613. if err != nil {
  614. //TODO: handle it
  615. return nil
  616. }
  617. return w.WriteBytes(b)
  618. }
  619. return w.WriteLine(cert.String())
  620. }
  621. func sshPrintTunnel(ifce *Interface, fs interface{}, a []string, w sshd.StringWriter) error {
  622. args, ok := fs.(*sshPrintTunnelFlags)
  623. if !ok {
  624. //TODO: error
  625. return nil
  626. }
  627. if len(a) == 0 {
  628. return w.WriteLine("No vpn ip was provided")
  629. }
  630. parsedIp := net.ParseIP(a[0])
  631. if parsedIp == nil {
  632. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  633. }
  634. vpnIp := ip2int(parsedIp)
  635. if vpnIp == 0 {
  636. return w.WriteLine(fmt.Sprintf("The provided vpn ip could not be parsed: %s", a[0]))
  637. }
  638. hostInfo, err := ifce.hostMap.QueryVpnIP(vpnIp)
  639. if err != nil {
  640. return w.WriteLine(fmt.Sprintf("Could not find tunnel for vpn ip: %v", a[0]))
  641. }
  642. enc := json.NewEncoder(w.GetWriter())
  643. if args.Pretty {
  644. enc.SetIndent("", " ")
  645. }
  646. return enc.Encode(copyHostInfo(hostInfo, ifce.hostMap.preferredRanges))
  647. }
  648. func sshReload(fs interface{}, a []string, w sshd.StringWriter) error {
  649. p, err := os.FindProcess(os.Getpid())
  650. if err != nil {
  651. return w.WriteLine(err.Error())
  652. //TODO
  653. }
  654. err = p.Signal(syscall.SIGHUP)
  655. if err != nil {
  656. return w.WriteLine(err.Error())
  657. //TODO
  658. }
  659. return w.WriteLine("HUP sent")
  660. }