Skip to content

Commit b6f80ce

Browse files
LtmThinkLtmThink
authored andcommitted
change and add pgsql
1 parent 6796e49 commit b6f80ce

37 files changed

+920
-230
lines changed

README.md

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
## 简介
44

5-
SQLRecorder能够实时记录应用运行时产生的SQL查询以及语法错误,方便代码审计时对SQL注入的实时关注。
5+
SQLRecorder能够实时记录应用运行时产生的SQL查询以及结果,方便代码审计时对SQL注入的实时关注。
66

7-
SQLRecorder以代理的形式运行,区别于MySQL日志记录的查询,SQLRecorder能够更好的感知SQL查询及其查询结果,并能记录日志所不能记录的MySQL语法错误
7+
SQLRecorder以代理的形式运行,区别于数据库日志记录,SQLRecorder能够更好的实时感知SQL查询,并能记录查询结果及查询错误
88

9-
SQLRecorder目前支持MySQL数据库查询记录
9+
SQLRecorder目前支持MySQL、PostgreSQL数据库查询记录,后续计划拓展对更多数据库的支持
1010

1111
## 使用
1212

13-
### 1.命令行窗口监控
13+
### 1.MySQL监控
1414

1515
#### 运行指令
1616

@@ -28,19 +28,34 @@ sqlrecorder command -s 127.0.0.1:3306 -p 127.0.0.1:43306
2828

2929
Web应用程序作为客户端连接SQLRecorder,SQLRecorder将实时记录产生的SQL查询以及语法错误
3030

31-
![image-20250220113403898](./images/image-20250220113403898.png)
31+
![image-20250218143240663](./images/image-20250218143240663.png)
32+
33+
![image-20250218191241049](./images/image-20250218191241049.png)
3234

3335
#### 使用场景二
3436

3537
使用mysql命令行工具(或其他连接工具)作为客户端连接SQLRecorder,SQLRecorder将实时记录产生的SQL查询以及语法错误
3638

37-
![image-20250220113642002](./images/image-20250220113642002.png)
39+
![image-20250218143051353](./images/image-20250218143051353.png)
3840

39-
![image-20250220113735824](./images/image-20250220113735824.png)
41+
![image-20250218191517583](./images/image-20250218191517583.png)
4042

41-
## 注意
43+
### 2.PostgreSQL监控
4244

43-
1. 使用时关闭 SSL/TLS 连接
45+
#### 运行指令
46+
47+
```
48+
sqlrecorder command -t postgresql -s 127.0.0.1:5432 -p 127.0.0.1:45432
49+
```
50+
51+
该命令将使SQLRecorder作为代理端监听127.0.0.1:45432,并指定后续连接PostgreSQL服务端地址为127.0.0.1:5432
52+
53+
![image-20250405141520880](./images/image-20250405141520880.png)
4454

55+
#### 实时监控
4556

57+
![image-20250405141641580](./images/image-20250405141641580.png)
4658

59+
## 注意
60+
61+
1. 使用时关闭 SSL/TLS 连接

buffer/buffer.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package buffer
2+
3+
import (
4+
. "SQLRecorder/utils"
5+
"io"
6+
"net"
7+
"time"
8+
)
9+
10+
const defaultBufSize = 4096
11+
const maxCachedBufSize = 256 * 1024
12+
const maxPacketSize = 1<<24 - 1
13+
14+
// A Buffer which is used for both reading and writing.
15+
// This is possible since communication on each connection is synchronous.
16+
// In other words, we can't write and read simultaneously on the same connection.
17+
// The Buffer is similar to bufio.Reader / Writer but zero-copy-ish
18+
// Also highly optimized for this particular use case.
19+
// This Buffer is backed by two byte slices in a double-buffering scheme
20+
type Buffer struct {
21+
buf []byte // buf is a byte Buffer who's length and capacity are equal.
22+
nc net.Conn
23+
idx int
24+
length int
25+
timeout time.Duration
26+
dbuf [2][]byte // dbuf is an array with the two byte slices that back this Buffer
27+
flipcnt uint // flipccnt is the current Buffer counter for double-buffering
28+
}
29+
30+
// NewBuffer allocates and returns a new Buffer.
31+
func NewBuffer(nc net.Conn) Buffer {
32+
fg := make([]byte, defaultBufSize)
33+
return Buffer{
34+
buf: fg,
35+
nc: nc,
36+
dbuf: [2][]byte{fg, nil},
37+
}
38+
}
39+
40+
// Flip replaces the active Buffer with the background Buffer
41+
// this is a delayed Flip that simply increases the Buffer counter;
42+
// the actual Flip will be performed the next time we call `Buffer.Fill`
43+
func (b *Buffer) Flip() {
44+
b.flipcnt += 1
45+
}
46+
47+
// Fill reads into the Buffer until at least _need_ bytes are in it
48+
func (b *Buffer) Fill(need int) error {
49+
n := b.length
50+
// Fill packets into its double-buffering target: if we've called
51+
// Flip on this Buffer, we'll be copying to the background Buffer,
52+
// and then filling it with network packets; otherwise we'll just move
53+
// the contents of the current Buffer to the front before filling it
54+
dest := b.dbuf[b.flipcnt&1]
55+
56+
// grow Buffer if necessary to fit the whole message.
57+
if need > len(dest) {
58+
// Round up to the next multiple of the default size
59+
dest = make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
60+
61+
// if the allocated Buffer is not too large, move it to backing storage
62+
// to prevent extra allocations on applications that perform large reads
63+
if len(dest) <= maxCachedBufSize {
64+
b.dbuf[b.flipcnt&1] = dest
65+
}
66+
}
67+
68+
// if we're filling the fg Buffer, move the existing packets to the start of it.
69+
// if we're filling the bg Buffer, copy over the packets
70+
if n > 0 {
71+
copy(dest[:n], b.buf[b.idx:])
72+
}
73+
74+
b.buf = dest
75+
b.idx = 0
76+
77+
for {
78+
if b.timeout > 0 {
79+
if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
80+
return err
81+
}
82+
}
83+
84+
nn, err := b.nc.Read(b.buf[n:])
85+
n += nn
86+
87+
switch err {
88+
case nil:
89+
if n < need {
90+
continue
91+
}
92+
b.length = n
93+
return nil
94+
95+
case io.EOF:
96+
if n >= need {
97+
b.length = n
98+
return nil
99+
}
100+
return io.ErrUnexpectedEOF
101+
102+
default:
103+
return err
104+
}
105+
}
106+
}
107+
108+
// returns next N bytes from Buffer.
109+
// The returned slice is only guaranteed to be valid until the next read
110+
func (b *Buffer) ReadNext(need int) ([]byte, error) {
111+
if b.length < need {
112+
// refill
113+
if err := b.Fill(need); err != nil {
114+
return nil, err
115+
}
116+
}
117+
118+
offset := b.idx
119+
b.idx += need
120+
b.length -= need
121+
return b.buf[offset:b.idx], nil
122+
}
123+
124+
// TakeBuffer returns a Buffer with the requested size.
125+
// If possible, a slice from the existing Buffer is returned.
126+
// Otherwise a bigger Buffer is made.
127+
// Only one Buffer (total) can be used at a time.
128+
func (b *Buffer) TakeBuffer(length int) ([]byte, error) {
129+
if b.length > 0 {
130+
return nil, ErrBusyBuffer
131+
}
132+
133+
// test (cheap) general case first
134+
if length <= cap(b.buf) {
135+
return b.buf[:length], nil
136+
}
137+
138+
if length < maxPacketSize {
139+
b.buf = make([]byte, length)
140+
return b.buf, nil
141+
}
142+
143+
// Buffer is larger than we want to Store.
144+
return make([]byte, length), nil
145+
}
146+
147+
// TakeSmallBuffer is shortcut which can be used if length is
148+
// known to be smaller than defaultBufSize.
149+
// Only one Buffer (total) can be used at a time.
150+
func (b *Buffer) TakeSmallBuffer(length int) ([]byte, error) {
151+
if b.length > 0 {
152+
return nil, ErrBusyBuffer
153+
}
154+
return b.buf[:length], nil
155+
}
156+
157+
func (b *Buffer) ReadAll() ([]byte, error) {
158+
for {
159+
n, err := b.nc.Read(b.buf)
160+
if err != nil {
161+
return nil, err
162+
}
163+
return b.buf[:n], nil
164+
}
165+
}
166+
167+
// TakeCompleteBuffer returns the complete existing Buffer.
168+
// This can be used if the necessary Buffer size is unknown.
169+
// cap and len of the returned Buffer will be equal.
170+
// Only one Buffer (total) can be used at a time.
171+
func (b *Buffer) TakeCompleteBuffer() ([]byte, error) {
172+
if b.length > 0 {
173+
return nil, ErrBusyBuffer
174+
}
175+
return b.buf, nil
176+
}
177+
178+
// Store stores buf, an updated Buffer, if its suitable to do so.
179+
func (b *Buffer) Store(buf []byte) error {
180+
if b.length > 0 {
181+
return ErrBusyBuffer
182+
} else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) {
183+
b.buf = buf[:cap(buf)]
184+
}
185+
return nil
186+
}

images/image-20250213203303123.png

1010 KB
Loading

images/image-20250213203351348.png

199 KB
Loading

images/image-20250213203402153.png

1 MB
Loading

images/image-20250213203504045.png

1.3 MB
Loading

images/image-20250213203512721.png

1.04 MB
Loading

images/image-20250218143051353.png

1.1 MB
Loading

images/image-20250218143240663.png

228 KB
Loading

images/image-20250218191241049.png

1.09 MB
Loading

0 commit comments

Comments
 (0)