netexec.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package main
  14. import (
  15. "encoding/json"
  16. "flag"
  17. "fmt"
  18. "io"
  19. "io/ioutil"
  20. "log"
  21. "net"
  22. "net/http"
  23. "net/url"
  24. "os"
  25. "os/exec"
  26. "strconv"
  27. "strings"
  28. "sync/atomic"
  29. "time"
  30. utilnet "k8s.io/apimachinery/pkg/util/net"
  31. )
  32. var (
  33. httpPort = 8080
  34. udpPort = 8081
  35. shellPath = "/bin/sh"
  36. serverReady = &atomicBool{0}
  37. )
  38. // atomicBool uses load/store operations on an int32 to simulate an atomic boolean.
  39. type atomicBool struct {
  40. v int32
  41. }
  42. // set sets the int32 to the given boolean.
  43. func (a *atomicBool) set(value bool) {
  44. if value {
  45. atomic.StoreInt32(&a.v, 1)
  46. return
  47. }
  48. atomic.StoreInt32(&a.v, 0)
  49. }
  50. // get returns true if the int32 == 1
  51. func (a *atomicBool) get() bool {
  52. return atomic.LoadInt32(&a.v) == 1
  53. }
  54. func init() {
  55. flag.IntVar(&httpPort, "http-port", 8080, "HTTP Listen Port")
  56. flag.IntVar(&udpPort, "udp-port", 8081, "UDP Listen Port")
  57. }
  58. func main() {
  59. flag.Parse()
  60. go startUDPServer(udpPort)
  61. startHTTPServer(httpPort)
  62. }
  63. func startHTTPServer(httpPort int) {
  64. http.HandleFunc("/", rootHandler)
  65. http.HandleFunc("/clientip", clientIPHandler)
  66. http.HandleFunc("/echo", echoHandler)
  67. http.HandleFunc("/exit", exitHandler)
  68. http.HandleFunc("/hostname", hostnameHandler)
  69. http.HandleFunc("/shell", shellHandler)
  70. http.HandleFunc("/upload", uploadHandler)
  71. http.HandleFunc("/dial", dialHandler)
  72. http.HandleFunc("/healthz", healthzHandler)
  73. // older handlers
  74. http.HandleFunc("/hostName", hostNameHandler)
  75. http.HandleFunc("/shutdown", shutdownHandler)
  76. log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", httpPort), nil))
  77. }
  78. func rootHandler(w http.ResponseWriter, r *http.Request) {
  79. log.Printf("GET /")
  80. fmt.Fprintf(w, "NOW: %v", time.Now())
  81. }
  82. func echoHandler(w http.ResponseWriter, r *http.Request) {
  83. log.Printf("GET /echo?msg=%s", r.FormValue("msg"))
  84. fmt.Fprintf(w, "%s", r.FormValue("msg"))
  85. }
  86. func clientIPHandler(w http.ResponseWriter, r *http.Request) {
  87. log.Printf("GET /clientip")
  88. fmt.Fprintf(w, r.RemoteAddr)
  89. }
  90. func exitHandler(w http.ResponseWriter, r *http.Request) {
  91. log.Printf("GET /exit?code=%s", r.FormValue("code"))
  92. code, err := strconv.Atoi(r.FormValue("code"))
  93. if err == nil || r.FormValue("code") == "" {
  94. os.Exit(code)
  95. }
  96. fmt.Fprintf(w, "argument 'code' must be an integer [0-127] or empty, got %q", r.FormValue("code"))
  97. }
  98. func hostnameHandler(w http.ResponseWriter, r *http.Request) {
  99. log.Printf("GET /hostname")
  100. fmt.Fprintf(w, getHostName())
  101. }
  102. // healthHandler response with a 200 if the UDP server is ready. It also serves
  103. // as a health check of the HTTP server by virtue of being a HTTP handler.
  104. func healthzHandler(w http.ResponseWriter, r *http.Request) {
  105. log.Printf("GET /healthz")
  106. if serverReady.get() {
  107. w.WriteHeader(200)
  108. return
  109. }
  110. w.WriteHeader(http.StatusPreconditionFailed)
  111. }
  112. func shutdownHandler(w http.ResponseWriter, r *http.Request) {
  113. log.Printf("GET /shutdown")
  114. os.Exit(0)
  115. }
  116. func dialHandler(w http.ResponseWriter, r *http.Request) {
  117. values, err := url.Parse(r.URL.RequestURI())
  118. if err != nil {
  119. http.Error(w, fmt.Sprintf("%v", err), http.StatusBadRequest)
  120. return
  121. }
  122. host := values.Query().Get("host")
  123. port := values.Query().Get("port")
  124. request := values.Query().Get("request") // hostName
  125. protocol := values.Query().Get("protocol")
  126. tryParam := values.Query().Get("tries")
  127. log.Printf("GET /dial?host=%s&protocol=%s&port=%s&request=%s&tries=%s", host, protocol, port, request, tryParam)
  128. tries := 1
  129. if len(tryParam) > 0 {
  130. tries, err = strconv.Atoi(tryParam)
  131. }
  132. if err != nil {
  133. http.Error(w, fmt.Sprintf("tries parameter is invalid. %v", err), http.StatusBadRequest)
  134. return
  135. }
  136. if len(request) == 0 {
  137. http.Error(w, fmt.Sprintf("request parameter not specified. %v", err), http.StatusBadRequest)
  138. return
  139. }
  140. if len(protocol) == 0 {
  141. protocol = "http"
  142. } else {
  143. protocol = strings.ToLower(protocol)
  144. }
  145. if protocol != "http" && protocol != "udp" {
  146. http.Error(w, fmt.Sprintf("unsupported protocol. %s", protocol), http.StatusBadRequest)
  147. return
  148. }
  149. hostPort := net.JoinHostPort(host, port)
  150. var udpAddress *net.UDPAddr
  151. if protocol == "udp" {
  152. udpAddress, err = net.ResolveUDPAddr("udp", hostPort)
  153. if err != nil {
  154. http.Error(w, fmt.Sprintf("host and/or port param are invalid. %v", err), http.StatusBadRequest)
  155. return
  156. }
  157. } else {
  158. _, err = net.ResolveTCPAddr("tcp", hostPort)
  159. if err != nil {
  160. http.Error(w, fmt.Sprintf("host and/or port param are invalid. %v", err), http.StatusBadRequest)
  161. return
  162. }
  163. }
  164. errors := make([]string, 0)
  165. responses := make([]string, 0)
  166. var response string
  167. for i := 0; i < tries; i++ {
  168. if protocol == "udp" {
  169. response, err = dialUDP(request, udpAddress)
  170. } else {
  171. response, err = dialHTTP(request, hostPort)
  172. }
  173. if err != nil {
  174. errors = append(errors, fmt.Sprintf("%v", err))
  175. } else {
  176. responses = append(responses, response)
  177. }
  178. }
  179. output := map[string][]string{}
  180. if len(response) > 0 {
  181. output["responses"] = responses
  182. }
  183. if len(errors) > 0 {
  184. output["errors"] = errors
  185. }
  186. bytes, err := json.Marshal(output)
  187. if err == nil {
  188. fmt.Fprintf(w, string(bytes))
  189. } else {
  190. http.Error(w, fmt.Sprintf("response could not be serialized. %v", err), http.StatusExpectationFailed)
  191. }
  192. }
  193. func dialHTTP(request, hostPort string) (string, error) {
  194. transport := utilnet.SetTransportDefaults(&http.Transport{})
  195. httpClient := createHTTPClient(transport)
  196. resp, err := httpClient.Get(fmt.Sprintf("http://%s/%s", hostPort, request))
  197. defer transport.CloseIdleConnections()
  198. if err == nil {
  199. defer resp.Body.Close()
  200. body, err := ioutil.ReadAll(resp.Body)
  201. if err == nil {
  202. return string(body), nil
  203. }
  204. }
  205. return "", err
  206. }
  207. func createHTTPClient(transport *http.Transport) *http.Client {
  208. client := &http.Client{
  209. Transport: transport,
  210. Timeout: 5 * time.Second,
  211. }
  212. return client
  213. }
  214. func dialUDP(request string, remoteAddress *net.UDPAddr) (string, error) {
  215. Conn, err := net.DialUDP("udp", nil, remoteAddress)
  216. if err != nil {
  217. return "", fmt.Errorf("udp dial failed. err:%v", err)
  218. }
  219. defer Conn.Close()
  220. buf := []byte(request)
  221. _, err = Conn.Write(buf)
  222. if err != nil {
  223. return "", fmt.Errorf("udp connection write failed. err:%v", err)
  224. }
  225. udpResponse := make([]byte, 1024)
  226. Conn.SetReadDeadline(time.Now().Add(5 * time.Second))
  227. count, err := Conn.Read(udpResponse)
  228. if err != nil || count == 0 {
  229. return "", fmt.Errorf("reading from udp connection failed. err:'%v'", err)
  230. }
  231. return string(udpResponse[0:count]), nil
  232. }
  233. func shellHandler(w http.ResponseWriter, r *http.Request) {
  234. cmd := r.FormValue("shellCommand")
  235. if cmd == "" {
  236. cmd = r.FormValue("cmd")
  237. }
  238. log.Printf("GET /shell?cmd=%s", cmd)
  239. cmdOut, err := exec.Command(shellPath, "-c", cmd).CombinedOutput()
  240. output := map[string]string{}
  241. if len(cmdOut) > 0 {
  242. output["output"] = string(cmdOut)
  243. }
  244. if err != nil {
  245. output["error"] = fmt.Sprintf("%v", err)
  246. }
  247. log.Printf("Output: %s", output)
  248. bytes, err := json.Marshal(output)
  249. if err == nil {
  250. fmt.Fprintf(w, string(bytes))
  251. } else {
  252. http.Error(w, fmt.Sprintf("response could not be serialized. %v", err), http.StatusExpectationFailed)
  253. }
  254. }
  255. func uploadHandler(w http.ResponseWriter, r *http.Request) {
  256. log.Printf("GET /upload")
  257. result := map[string]string{}
  258. file, _, err := r.FormFile("file")
  259. if err != nil {
  260. result["error"] = "Unable to upload file."
  261. bytes, err := json.Marshal(result)
  262. if err == nil {
  263. fmt.Fprintf(w, string(bytes))
  264. } else {
  265. http.Error(w, fmt.Sprintf("%s. Also unable to serialize output. %v", result["error"], err), http.StatusInternalServerError)
  266. }
  267. log.Printf("Unable to upload file: %s", err)
  268. return
  269. }
  270. defer file.Close()
  271. f, err := ioutil.TempFile("/uploads", "upload")
  272. if err != nil {
  273. result["error"] = "Unable to open file for write"
  274. bytes, err := json.Marshal(result)
  275. if err == nil {
  276. fmt.Fprintf(w, string(bytes))
  277. } else {
  278. http.Error(w, fmt.Sprintf("%s. Also unable to serialize output. %v", result["error"], err), http.StatusInternalServerError)
  279. }
  280. log.Printf("Unable to open file for write: %s", err)
  281. return
  282. }
  283. defer f.Close()
  284. if _, err = io.Copy(f, file); err != nil {
  285. result["error"] = "Unable to write file."
  286. bytes, err := json.Marshal(result)
  287. if err == nil {
  288. fmt.Fprintf(w, string(bytes))
  289. } else {
  290. http.Error(w, fmt.Sprintf("%s. Also unable to serialize output. %v", result["error"], err), http.StatusInternalServerError)
  291. }
  292. log.Printf("Unable to write file: %s", err)
  293. return
  294. }
  295. UploadFile := f.Name()
  296. if err := os.Chmod(UploadFile, 0700); err != nil {
  297. result["error"] = "Unable to chmod file."
  298. bytes, err := json.Marshal(result)
  299. if err == nil {
  300. fmt.Fprintf(w, string(bytes))
  301. } else {
  302. http.Error(w, fmt.Sprintf("%s. Also unable to serialize output. %v", result["error"], err), http.StatusInternalServerError)
  303. }
  304. log.Printf("Unable to chmod file: %s", err)
  305. return
  306. }
  307. log.Printf("Wrote upload to %s", UploadFile)
  308. result["output"] = UploadFile
  309. w.WriteHeader(http.StatusCreated)
  310. bytes, err := json.Marshal(result)
  311. fmt.Fprintf(w, string(bytes))
  312. }
  313. func hostNameHandler(w http.ResponseWriter, r *http.Request) {
  314. log.Printf("GET /hostName")
  315. fmt.Fprintf(w, getHostName())
  316. }
  317. // udp server supports the hostName, echo and clientIP commands.
  318. func startUDPServer(udpPort int) {
  319. serverAddress, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", udpPort))
  320. assertNoError(err)
  321. serverConn, err := net.ListenUDP("udp", serverAddress)
  322. assertNoError(err)
  323. defer serverConn.Close()
  324. buf := make([]byte, 1024)
  325. log.Printf("Started UDP server")
  326. // Start responding to readiness probes.
  327. serverReady.set(true)
  328. defer func() {
  329. log.Printf("UDP server exited")
  330. serverReady.set(false)
  331. }()
  332. for {
  333. n, clientAddress, err := serverConn.ReadFromUDP(buf)
  334. assertNoError(err)
  335. receivedText := strings.ToLower(strings.TrimSpace(string(buf[0:n])))
  336. if receivedText == "hostname" {
  337. log.Println("Sending udp hostName response")
  338. _, err = serverConn.WriteToUDP([]byte(getHostName()), clientAddress)
  339. assertNoError(err)
  340. } else if strings.HasPrefix(receivedText, "echo ") {
  341. parts := strings.SplitN(receivedText, " ", 2)
  342. resp := ""
  343. if len(parts) == 2 {
  344. resp = parts[1]
  345. }
  346. log.Printf("Echoing %v\n", resp)
  347. _, err = serverConn.WriteToUDP([]byte(resp), clientAddress)
  348. assertNoError(err)
  349. } else if receivedText == "clientip" {
  350. log.Printf("Sending back clientip to %s", clientAddress.String())
  351. _, err = serverConn.WriteToUDP([]byte(clientAddress.String()), clientAddress)
  352. assertNoError(err)
  353. } else if len(receivedText) > 0 {
  354. log.Printf("Unknown udp command received: %v\n", receivedText)
  355. }
  356. }
  357. }
  358. func getHostName() string {
  359. hostName, err := os.Hostname()
  360. assertNoError(err)
  361. return hostName
  362. }
  363. func assertNoError(err error) {
  364. if err != nil {
  365. log.Fatal("Error occurred. error:", err)
  366. }
  367. }