cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2019.11.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

cmd/sqlgateway/sqlgateway.go

148lines · modeblame

4e1df1a2Adam Chalmers6 years ago1package sqlgateway
2
3import (
4"database/sql"
5"encoding/json"
6"fmt"
7"math/rand"
8"net/http"
9"strings"
10"time"
11
12_ "github.com/lib/pq"
13cli "gopkg.in/urfave/cli.v2"
14
15"github.com/elgs/gosqljson"
16
17"github.com/gorilla/mux"
18"github.com/sirupsen/logrus"
19)
20
21type Message struct {
22Connection Connection `json:"connection"`
23Command string `json:"command"`
24Params []interface{} `json:"params"`
25}
26
27type Connection struct {
28SSLMode string `json:"sslmode"`
29Token string `json:"token"`
30}
31
32type Response struct {
33Columns []string `json:"columns"`
34Rows [][]string `json:"rows"`
35Error string `json:"error"`
36}
37
38type Proxy struct {
39Context *cli.Context
40Router *mux.Router
41Token string
42User string
43Password string
44Driver string
45Database string
46Logger *logrus.Logger
47}
48
49func StartProxy(c *cli.Context, logger *logrus.Logger, password string) error {
50proxy := NewProxy(c, logger, password)
51
52logger.Infof("Starting SQL Gateway Proxy on port %s", strings.Split(c.String("url"), ":")[1])
53
54err := http.ListenAndServe(":"+strings.Split(c.String("url"), ":")[1], proxy.Router)
55if err != nil {
56return err
57}
58
59return nil
60}
61
62func randID(n int, c *cli.Context) string {
63charBytes := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
64b := make([]byte, n)
65for i := range b {
66b[i] = charBytes[rand.Intn(len(charBytes))]
67}
68return fmt.Sprintf("%s&%s", c.String("hostname"), b)
69}
70
71// db://user@dbname
72func parseInfo(input string) (string, string, string) {
73p1 := strings.Split(input, "://")
74p2 := strings.Split(p1[1], "@")
75return p1[0], p2[0], p2[1]
76}
77
78func NewProxy(c *cli.Context, logger *logrus.Logger, pass string) *Proxy {
79rand.Seed(time.Now().UnixNano())
80driver, user, dbname := parseInfo(c.String("address"))
81proxy := Proxy{
82Context: c,
83Router: mux.NewRouter(),
84Token: randID(64, c),
85Logger: logger,
86User: user,
87Password: pass,
88Database: dbname,
89Driver: driver,
90}
91
92logger.Info(fmt.Sprintf(`
93
94--------------------
95SQL Gateway Proxy
96Token: %s
97--------------------
98
99`, proxy.Token))
100
101proxy.Router.HandleFunc("/", proxy.proxyRequest).Methods("POST")
102return &proxy
103}
104
105func (proxy *Proxy) proxyRequest(rw http.ResponseWriter, req *http.Request) {
106var message Message
107response := Response{}
108
109err := json.NewDecoder(req.Body).Decode(&message)
110if err != nil {
111proxy.Logger.Error(err)
112http.Error(rw, fmt.Sprintf("400 - %s", err.Error()), http.StatusBadRequest)
113return
114}
115
116if message.Connection.Token != proxy.Token {
117proxy.Logger.Error("Invalid token")
118http.Error(rw, "400 - Invalid token", http.StatusBadRequest)
119return
120}
121
122connStr := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s", proxy.User, proxy.Password, proxy.Database, message.Connection.SSLMode)
123
124db, err := sql.Open(proxy.Driver, connStr)
125defer db.Close()
126
127if err != nil {
128proxy.Logger.Error(err)
129http.Error(rw, fmt.Sprintf("400 - %s", err.Error()), http.StatusBadRequest)
130return
131
132} else {
133proxy.Logger.Info("Forwarding SQL: ", message.Command)
134rw.Header().Set("Content-Type", "application/json")
135
136headers, data, err := gosqljson.QueryDbToArray(db, "lower", message.Command, message.Params...)
137
138if err != nil {
139proxy.Logger.Error(err)
140http.Error(rw, fmt.Sprintf("400 - %s", err.Error()), http.StatusBadRequest)
141return
142
143} else {
144response = Response{headers, data, ""}
145}
146}
147json.NewEncoder(rw).Encode(response)
148}