mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-06-03 15:04:47 +00:00
Compare commits
14 Commits
32.0-dev5
...
32.0-dev15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f89690da6 | ||
|
|
3e47abf208 | ||
|
|
3cbccccb8b | ||
|
|
08ae2bf6d7 | ||
|
|
684c51686f | ||
|
|
1de50b0572 | ||
|
|
0881dad17f | ||
|
|
cade960b9b | ||
|
|
d3e6a69d82 | ||
|
|
ed9e162af0 | ||
|
|
4e22e77597 | ||
|
|
3978ace4ef | ||
|
|
e71a12d399 | ||
|
|
90c54f9505 |
60
.github/workflows/static_code_analysis.yml
vendored
60
.github/workflows/static_code_analysis.yml
vendored
@@ -10,7 +10,7 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
golangci:
|
go-lint:
|
||||||
name: Go lint
|
name: Go lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -141,3 +141,61 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap/extensions/redis
|
working-directory: tap/extensions/redis
|
||||||
|
|
||||||
|
- name: Check logger modified files
|
||||||
|
id: logger_modified_files
|
||||||
|
run: devops/check_modified_files.sh logger/
|
||||||
|
|
||||||
|
- name: Go lint - logger
|
||||||
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.logger_modified_files.outputs.matched == 'true'
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
working-directory: logger
|
||||||
|
|
||||||
|
es-lint:
|
||||||
|
name: ES lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
|
||||||
|
- name: Check modified UI files
|
||||||
|
id: ui_modified_files
|
||||||
|
run: devops/check_modified_files.sh ui/
|
||||||
|
|
||||||
|
- name: ESLint prerequisites ui
|
||||||
|
if: steps.ui_modified_files.outputs.matched == 'true'
|
||||||
|
run: |
|
||||||
|
sudo npm install -g eslint
|
||||||
|
cd ui
|
||||||
|
npm run prestart
|
||||||
|
npm i
|
||||||
|
|
||||||
|
- name: ESLint ui
|
||||||
|
if: steps.ui_modified_files.outputs.matched == 'true'
|
||||||
|
run: |
|
||||||
|
cd ui
|
||||||
|
npm run eslint
|
||||||
|
|
||||||
|
- name: Check modified ui-common files
|
||||||
|
id: ui_common_modified_files
|
||||||
|
run: devops/check_modified_files.sh ui-common/
|
||||||
|
|
||||||
|
- name: ESLint prerequisites ui-common
|
||||||
|
if: steps.ui_common_modified_files.outputs.matched == 'true'
|
||||||
|
run: |
|
||||||
|
sudo npm install -g eslint
|
||||||
|
cd ui-common
|
||||||
|
npm i
|
||||||
|
|
||||||
|
- name: ESLint ui-common
|
||||||
|
if: steps.ui_common_modified_files.outputs.matched == 'true'
|
||||||
|
run: |
|
||||||
|
cd ui-common
|
||||||
|
npm run eslint
|
||||||
|
|||||||
@@ -44,11 +44,18 @@ ENV CGO_ENABLED=1 GOOS=linux
|
|||||||
ENV GOARCH=arm64 CGO_CFLAGS="-I/work/libpcap"
|
ENV GOARCH=arm64 CGO_CFLAGS="-I/work/libpcap"
|
||||||
|
|
||||||
|
|
||||||
|
### Builder image for AArch64 to x86-64 cross-compilation
|
||||||
|
FROM up9inc/linux-x86_64-musl-go-libpcap AS builder-from-arm64v8-to-amd64
|
||||||
|
ENV CGO_ENABLED=1 GOOS=linux
|
||||||
|
ENV GOARCH=amd64 CGO_CFLAGS="-I/libpcap"
|
||||||
|
|
||||||
|
|
||||||
### Final builder image where the build happens
|
### Final builder image where the build happens
|
||||||
# Possible build strategies:
|
# Possible build strategies:
|
||||||
# BUILDARCH=amd64 TARGETARCH=amd64
|
# BUILDARCH=amd64 TARGETARCH=amd64
|
||||||
# BUILDARCH=arm64v8 TARGETARCH=arm64v8
|
# BUILDARCH=arm64v8 TARGETARCH=arm64v8
|
||||||
# BUILDARCH=amd64 TARGETARCH=arm64v8
|
# BUILDARCH=amd64 TARGETARCH=arm64v8
|
||||||
|
# BUILDARCH=arm64v8 TARGETARCH=amd64
|
||||||
ARG BUILDARCH=amd64
|
ARG BUILDARCH=amd64
|
||||||
ARG TARGETARCH=amd64
|
ARG TARGETARCH=amd64
|
||||||
FROM builder-from-${BUILDARCH}-to-${TARGETARCH} AS builder
|
FROM builder-from-${BUILDARCH}-to-${TARGETARCH} AS builder
|
||||||
@@ -66,8 +73,6 @@ COPY tap/extensions/http/go.mod ../tap/extensions/http/
|
|||||||
COPY tap/extensions/kafka/go.mod ../tap/extensions/kafka/
|
COPY tap/extensions/kafka/go.mod ../tap/extensions/kafka/
|
||||||
COPY tap/extensions/redis/go.mod ../tap/extensions/redis/
|
COPY tap/extensions/redis/go.mod ../tap/extensions/redis/
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
# cheap trick to make the build faster (as long as go.mod did not change)
|
|
||||||
RUN go list -f '{{.Path}}@{{.Version}}' -m all | sed 1d | grep -e 'go-cache' | xargs go get
|
|
||||||
|
|
||||||
# Copy and build agent code
|
# Copy and build agent code
|
||||||
COPY shared ../shared
|
COPY shared ../shared
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ require (
|
|||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/up9inc/mizu/logger v0.0.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
|
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
|
||||||
@@ -48,6 +49,8 @@ require (
|
|||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
|
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ require (
|
|||||||
github.com/nav-inc/datetime v0.1.3
|
github.com/nav-inc/datetime v0.1.3
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/orcaman/concurrent-map v1.0.0
|
github.com/orcaman/concurrent-map v1.0.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607
|
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607
|
||||||
github.com/up9inc/mizu/logger v0.0.0
|
github.com/up9inc/mizu/logger v0.0.0
|
||||||
@@ -86,6 +85,7 @@ require (
|
|||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/mertyildiran/gqlparser/v2 v2.4.6 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/moby/spdystream v0.2.0 // indirect
|
github.com/moby/spdystream v0.2.0 // indirect
|
||||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||||
@@ -111,7 +111,7 @@ require (
|
|||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||||
github.com/xlab/treeprint v1.1.0 // indirect
|
github.com/xlab/treeprint v1.1.0 // indirect
|
||||||
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
|
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect
|
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b // indirect
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
|
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
|
|||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
|
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
@@ -493,6 +494,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/mertyildiran/gqlparser/v2 v2.4.6 h1:enAq4F5PYgW/rYExPNzYt7IYrrZnzrfqdywMA1QdFtM=
|
||||||
|
github.com/mertyildiran/gqlparser/v2 v2.4.6/go.mod h1:XZId58F+XqRSmoLrdsOLgqA918oNvBzuOORruJWBjDo=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
@@ -751,8 +754,9 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
|||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
|
|
||||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b h1:Qwe1rC8PSniVfAFPFJeyUkB+zcysC3RgJBAGk7eqBEU=
|
||||||
|
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
|||||||
@@ -219,8 +219,6 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
|||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
|||||||
31
devops/linux-x86_64-musl-go-libpcap/Dockerfile
Normal file
31
devops/linux-x86_64-musl-go-libpcap/Dockerfile
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
FROM messense/rust-musl-cross:x86_64-musl AS builder-from-arm64v8-to-amd64
|
||||||
|
|
||||||
|
ENV CROSS_TRIPLE x86_64-unknown-linux-musl
|
||||||
|
ENV CROSS_ROOT /usr/local/musl
|
||||||
|
|
||||||
|
ENV AS=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-as \
|
||||||
|
AR=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-ar \
|
||||||
|
CC=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-gcc \
|
||||||
|
CPP=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-cpp \
|
||||||
|
CXX=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-g++ \
|
||||||
|
LD=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-ld \
|
||||||
|
FC=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-gfortran
|
||||||
|
|
||||||
|
# Install Go
|
||||||
|
WORKDIR /
|
||||||
|
RUN curl https://go.dev/dl/go1.17.6.linux-arm64.tar.gz -Lo ./go.linux-arm64.tar.gz \
|
||||||
|
&& curl https://go.dev/dl/go1.17.6.linux-arm64.tar.gz.asc -Lo ./go.linux-arm64.tar.gz.asc \
|
||||||
|
&& curl https://dl.google.com/dl/linux/linux_signing_key.pub -Lo linux_signing_key.pub \
|
||||||
|
&& gpg --import linux_signing_key.pub && gpg --verify ./go.linux-arm64.tar.gz.asc ./go.linux-arm64.tar.gz \
|
||||||
|
&& rm -rf /usr/local/go && tar -C /usr/local -xzf go.linux-arm64.tar.gz
|
||||||
|
ENV PATH "$PATH:/usr/local/go/bin"
|
||||||
|
|
||||||
|
# Compile libpcap from source
|
||||||
|
RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz -Lo ./libpcap.tar.gz \
|
||||||
|
&& curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz.sig -Lo ./libpcap.tar.gz.sig \
|
||||||
|
&& curl https://www.tcpdump.org/release/signing-key.asc -Lo ./signing-key.asc \
|
||||||
|
&& gpg --import signing-key.asc && gpg --verify libpcap.tar.gz.sig libpcap.tar.gz \
|
||||||
|
&& tar -xzf libpcap.tar.gz && mv ./libpcap-* ./libpcap
|
||||||
|
WORKDIR /libpcap
|
||||||
|
RUN ./configure --host=x86_64 && make \
|
||||||
|
&& cp /libpcap/libpcap.a /usr/local/musl/lib/gcc/x86_64-unknown-linux-musl/*/
|
||||||
4
devops/linux-x86_64-musl-go-libpcap/build-push.sh
Executable file
4
devops/linux-x86_64-musl-go-libpcap/build-push.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
docker build . -t up9inc/linux-x86_64-musl-go-libpcap && docker push up9inc/linux-x86_64-musl-go-libpcap
|
||||||
12
devops/ui-common-pack.sh
Executable file
12
devops/ui-common-pack.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# exit when any command fails
|
||||||
|
set -e
|
||||||
|
|
||||||
|
dst_folder=$1
|
||||||
|
echo "dst folder: $dst_folder";
|
||||||
|
|
||||||
|
cd $dst_folder/../ui-common
|
||||||
|
npm i
|
||||||
|
npm pack
|
||||||
|
mv up9-mizu-common-0.0.0.tgz $dst_folder
|
||||||
@@ -10,7 +10,6 @@ const (
|
|||||||
ValidationRulesFileName = "validation-rules.yaml"
|
ValidationRulesFileName = "validation-rules.yaml"
|
||||||
ContractFileName = "contract-oas.yaml"
|
ContractFileName = "contract-oas.yaml"
|
||||||
ConfigFileName = "mizu-config.json"
|
ConfigFileName = "mizu-config.json"
|
||||||
GoGCEnvVar = "GOGC"
|
|
||||||
DefaultApiServerPort = 8899
|
DefaultApiServerPort = 8899
|
||||||
LogLevelEnvVar = "LOG_LEVEL"
|
LogLevelEnvVar = "LOG_LEVEL"
|
||||||
MizuAgentImageRepo = "docker.io/up9inc/mizu"
|
MizuAgentImageRepo = "docker.io/up9inc/mizu"
|
||||||
|
|||||||
@@ -768,7 +768,6 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
|
|||||||
agentContainer.WithEnv(
|
agentContainer.WithEnv(
|
||||||
applyconfcore.EnvVar().WithName(shared.LogLevelEnvVar).WithValue(logLevel.String()),
|
applyconfcore.EnvVar().WithName(shared.LogLevelEnvVar).WithValue(logLevel.String()),
|
||||||
applyconfcore.EnvVar().WithName(shared.HostModeEnvVar).WithValue("1"),
|
applyconfcore.EnvVar().WithName(shared.HostModeEnvVar).WithValue("1"),
|
||||||
applyconfcore.EnvVar().WithName(shared.GoGCEnvVar).WithValue("12800"),
|
|
||||||
applyconfcore.EnvVar().WithName(shared.MizuFilteringOptionsEnvVar).WithValue(string(mizuApiFilteringOptionsJsonStr)),
|
applyconfcore.EnvVar().WithName(shared.MizuFilteringOptionsEnvVar).WithValue(string(mizuApiFilteringOptionsJsonStr)),
|
||||||
)
|
)
|
||||||
agentContainer.WithEnv(
|
agentContainer.WithEnv(
|
||||||
|
|||||||
@@ -104,11 +104,7 @@ type OutputChannelItem struct {
|
|||||||
Namespace string
|
Namespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SuperTimer struct {
|
type ProtoIdentifier struct {
|
||||||
CaptureTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type SuperIdentifier struct {
|
|
||||||
Protocol *Protocol
|
Protocol *Protocol
|
||||||
IsClosedOthers bool
|
IsClosedOthers bool
|
||||||
}
|
}
|
||||||
@@ -130,7 +126,7 @@ func (p *ReadProgress) Current() (n int) {
|
|||||||
type Dissector interface {
|
type Dissector interface {
|
||||||
Register(*Extension)
|
Register(*Extension)
|
||||||
Ping()
|
Ping()
|
||||||
Dissect(b *bufio.Reader, progress *ReadProgress, capture Capture, isClient bool, tcpID *TcpID, counterPair *CounterPair, superTimer *SuperTimer, superIdentifier *SuperIdentifier, emitter Emitter, options *TrafficFilteringOptions, reqResMatcher RequestResponseMatcher) error
|
Dissect(b *bufio.Reader, reader TcpReader, options *TrafficFilteringOptions) error
|
||||||
Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *Entry
|
Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *Entry
|
||||||
Summarize(entry *Entry) *BaseEntry
|
Summarize(entry *Entry) *BaseEntry
|
||||||
Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error)
|
Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error)
|
||||||
@@ -406,3 +402,39 @@ func (r *HTTPResponseWrapper) MarshalJSON() ([]byte, error) {
|
|||||||
Response: r.Response,
|
Response: r.Response,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TcpReaderDataMsg interface {
|
||||||
|
GetBytes() []byte
|
||||||
|
GetTimestamp() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type TcpReader interface {
|
||||||
|
Read(p []byte) (int, error)
|
||||||
|
GetReqResMatcher() RequestResponseMatcher
|
||||||
|
GetIsClient() bool
|
||||||
|
GetReadProgress() *ReadProgress
|
||||||
|
GetParent() TcpStream
|
||||||
|
GetTcpID() *TcpID
|
||||||
|
GetCounterPair() *CounterPair
|
||||||
|
GetCaptureTime() time.Time
|
||||||
|
GetEmitter() Emitter
|
||||||
|
GetIsClosed() bool
|
||||||
|
GetExtension() *Extension
|
||||||
|
}
|
||||||
|
|
||||||
|
type TcpStream interface {
|
||||||
|
SetProtocol(protocol *Protocol)
|
||||||
|
GetOrigin() Capture
|
||||||
|
GetProtoIdentifier() *ProtoIdentifier
|
||||||
|
GetReqResMatchers() []RequestResponseMatcher
|
||||||
|
GetIsTapTarget() bool
|
||||||
|
GetIsClosed() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type TcpStreamMap interface {
|
||||||
|
Range(f func(key, value interface{}) bool)
|
||||||
|
Store(key, value interface{})
|
||||||
|
Delete(key interface{})
|
||||||
|
NextId() int64
|
||||||
|
CloseTimedoutTcpStreamChannels()
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type Cleaner struct {
|
|||||||
connectionTimeout time.Duration
|
connectionTimeout time.Duration
|
||||||
stats CleanerStats
|
stats CleanerStats
|
||||||
statsMutex sync.Mutex
|
statsMutex sync.Mutex
|
||||||
streamsMap *tcpStreamMap
|
streamsMap api.TcpStreamMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cl *Cleaner) clean() {
|
func (cl *Cleaner) clean() {
|
||||||
@@ -33,13 +33,15 @@ func (cl *Cleaner) clean() {
|
|||||||
flushed, closed := cl.assembler.FlushCloseOlderThan(startCleanTime.Add(-cl.connectionTimeout))
|
flushed, closed := cl.assembler.FlushCloseOlderThan(startCleanTime.Add(-cl.connectionTimeout))
|
||||||
cl.assemblerMutex.Unlock()
|
cl.assemblerMutex.Unlock()
|
||||||
|
|
||||||
cl.streamsMap.streams.Range(func(k, v interface{}) bool {
|
cl.streamsMap.Range(func(k, v interface{}) bool {
|
||||||
reqResMatcher := v.(*tcpStreamWrapper).reqResMatcher
|
reqResMatchers := v.(api.TcpStream).GetReqResMatchers()
|
||||||
if reqResMatcher == nil {
|
for _, reqResMatcher := range reqResMatchers {
|
||||||
return true
|
if reqResMatcher == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
deleted := deleteOlderThan(reqResMatcher.GetMap(), startCleanTime.Add(-cl.connectionTimeout))
|
||||||
|
cl.stats.deleted += deleted
|
||||||
}
|
}
|
||||||
deleted := deleteOlderThan(reqResMatcher.GetMap(), startCleanTime.Add(-cl.connectionTimeout))
|
|
||||||
cl.stats.deleted += deleted
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -39,17 +39,17 @@ func (d dissecting) Ping() {
|
|||||||
|
|
||||||
const amqpRequest string = "amqp_request"
|
const amqpRequest string = "amqp_request"
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error {
|
||||||
r := AmqpReader{b}
|
r := AmqpReader{b}
|
||||||
|
|
||||||
var remaining int
|
var remaining int
|
||||||
var header *HeaderFrame
|
var header *HeaderFrame
|
||||||
|
|
||||||
connectionInfo := &api.ConnectionInfo{
|
connectionInfo := &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: reader.GetTcpID().SrcIP,
|
||||||
ClientPort: tcpID.SrcPort,
|
ClientPort: reader.GetTcpID().SrcPort,
|
||||||
ServerIP: tcpID.DstIP,
|
ServerIP: reader.GetTcpID().DstIP,
|
||||||
ServerPort: tcpID.DstPort,
|
ServerPort: reader.GetTcpID().DstPort,
|
||||||
IsOutgoing: true,
|
IsOutgoing: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
var lastMethodFrameMessage Message
|
var lastMethodFrameMessage Message
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if superIdentifier.Protocol != nil && superIdentifier.Protocol != &protocol {
|
if reader.GetParent().GetProtoIdentifier().Protocol != nil && reader.GetParent().GetProtoIdentifier().Protocol != &protocol {
|
||||||
return errors.New("Identified by another protocol")
|
return errors.New("Identified by another protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,12 +112,12 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
switch lastMethodFrameMessage.(type) {
|
switch lastMethodFrameMessage.(type) {
|
||||||
case *BasicPublish:
|
case *BasicPublish:
|
||||||
eventBasicPublish.Body = f.Body
|
eventBasicPublish.Body = f.Body
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventBasicPublish, amqpRequest, basicMethodMap[40], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventBasicPublish, amqpRequest, basicMethodMap[40], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
case *BasicDeliver:
|
case *BasicDeliver:
|
||||||
eventBasicDeliver.Body = f.Body
|
eventBasicDeliver.Body = f.Body
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventBasicDeliver, amqpRequest, basicMethodMap[60], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventBasicDeliver, amqpRequest, basicMethodMap[60], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
}
|
}
|
||||||
|
|
||||||
case *MethodFrame:
|
case *MethodFrame:
|
||||||
@@ -137,8 +137,8 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventQueueBind, amqpRequest, queueMethodMap[20], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventQueueBind, amqpRequest, queueMethodMap[20], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
|
|
||||||
case *BasicConsume:
|
case *BasicConsume:
|
||||||
eventBasicConsume := &BasicConsume{
|
eventBasicConsume := &BasicConsume{
|
||||||
@@ -150,8 +150,8 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventBasicConsume, amqpRequest, basicMethodMap[20], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventBasicConsume, amqpRequest, basicMethodMap[20], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
|
|
||||||
case *BasicDeliver:
|
case *BasicDeliver:
|
||||||
eventBasicDeliver.ConsumerTag = m.ConsumerTag
|
eventBasicDeliver.ConsumerTag = m.ConsumerTag
|
||||||
@@ -170,8 +170,8 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventQueueDeclare, amqpRequest, queueMethodMap[10], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventQueueDeclare, amqpRequest, queueMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
|
|
||||||
case *ExchangeDeclare:
|
case *ExchangeDeclare:
|
||||||
eventExchangeDeclare := &ExchangeDeclare{
|
eventExchangeDeclare := &ExchangeDeclare{
|
||||||
@@ -184,8 +184,8 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
NoWait: m.NoWait,
|
NoWait: m.NoWait,
|
||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventExchangeDeclare, amqpRequest, exchangeMethodMap[10], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventExchangeDeclare, amqpRequest, exchangeMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
|
|
||||||
case *ConnectionStart:
|
case *ConnectionStart:
|
||||||
eventConnectionStart := &ConnectionStart{
|
eventConnectionStart := &ConnectionStart{
|
||||||
@@ -195,8 +195,8 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
Mechanisms: m.Mechanisms,
|
Mechanisms: m.Mechanisms,
|
||||||
Locales: m.Locales,
|
Locales: m.Locales,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventConnectionStart, amqpRequest, connectionMethodMap[10], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventConnectionStart, amqpRequest, connectionMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
|
|
||||||
case *ConnectionClose:
|
case *ConnectionClose:
|
||||||
eventConnectionClose := &ConnectionClose{
|
eventConnectionClose := &ConnectionClose{
|
||||||
@@ -205,8 +205,8 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
ClassId: m.ClassId,
|
ClassId: m.ClassId,
|
||||||
MethodId: m.MethodId,
|
MethodId: m.MethodId,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
reader.GetParent().SetProtocol(&protocol)
|
||||||
emitAMQP(*eventConnectionClose, amqpRequest, connectionMethodMap[50], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
emitAMQP(*eventConnectionClose, amqpRequest, connectionMethodMap[50], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ func TestDissect(t *testing.T) {
|
|||||||
Request: 0,
|
Request: 0,
|
||||||
Response: 0,
|
Response: 0,
|
||||||
}
|
}
|
||||||
superIdentifier := &api.SuperIdentifier{}
|
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
pathClient := _path
|
pathClient := _path
|
||||||
@@ -122,7 +121,21 @@ func TestDissect(t *testing.T) {
|
|||||||
DstPort: "2",
|
DstPort: "2",
|
||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
stream := NewTcpStream(api.Pcap)
|
||||||
|
reader := NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDClient,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferClient, reader, options)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -140,7 +153,20 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
reader = NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDServer,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferServer, reader, options)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
84
tap/extensions/amqp/tcp_reader_mock_test.go
Normal file
84
tap/extensions/amqp/tcp_reader_mock_test.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpReader struct {
|
||||||
|
ident string
|
||||||
|
tcpID *api.TcpID
|
||||||
|
isClosed bool
|
||||||
|
isClient bool
|
||||||
|
isOutgoing bool
|
||||||
|
progress *api.ReadProgress
|
||||||
|
captureTime time.Time
|
||||||
|
parent api.TcpStream
|
||||||
|
extension *api.Extension
|
||||||
|
emitter api.Emitter
|
||||||
|
counterPair *api.CounterPair
|
||||||
|
reqResMatcher api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpReader(progress *api.ReadProgress, ident string, tcpId *api.TcpID, captureTime time.Time, parent api.TcpStream, isClient bool, isOutgoing bool, extension *api.Extension, emitter api.Emitter, counterPair *api.CounterPair, reqResMatcher api.RequestResponseMatcher) api.TcpReader {
|
||||||
|
return &tcpReader{
|
||||||
|
progress: progress,
|
||||||
|
ident: ident,
|
||||||
|
tcpID: tcpId,
|
||||||
|
captureTime: captureTime,
|
||||||
|
parent: parent,
|
||||||
|
isClient: isClient,
|
||||||
|
isOutgoing: isOutgoing,
|
||||||
|
extension: extension,
|
||||||
|
emitter: emitter,
|
||||||
|
counterPair: counterPair,
|
||||||
|
reqResMatcher: reqResMatcher,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) Read(p []byte) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReqResMatcher() api.RequestResponseMatcher {
|
||||||
|
return reader.reqResMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClient() bool {
|
||||||
|
return reader.isClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReadProgress() *api.ReadProgress {
|
||||||
|
return reader.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetParent() api.TcpStream {
|
||||||
|
return reader.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetTcpID() *api.TcpID {
|
||||||
|
return reader.tcpID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCounterPair() *api.CounterPair {
|
||||||
|
return reader.counterPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCaptureTime() time.Time {
|
||||||
|
return reader.captureTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetEmitter() api.Emitter {
|
||||||
|
return reader.emitter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClosed() bool {
|
||||||
|
return reader.isClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetExtension() *api.Extension {
|
||||||
|
return reader.extension
|
||||||
|
}
|
||||||
45
tap/extensions/amqp/tcp_stream_mock_test.go
Normal file
45
tap/extensions/amqp/tcp_stream_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpStream struct {
|
||||||
|
isClosed bool
|
||||||
|
protoIdentifier *api.ProtoIdentifier
|
||||||
|
isTapTarget bool
|
||||||
|
origin api.Capture
|
||||||
|
reqResMatchers []api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpStream(capture api.Capture) api.TcpStream {
|
||||||
|
return &tcpStream{
|
||||||
|
origin: capture,
|
||||||
|
protoIdentifier: &api.ProtoIdentifier{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) SetProtocol(protocol *api.Protocol) {}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetOrigin() api.Capture {
|
||||||
|
return t.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetProtoIdentifier() *api.ProtoIdentifier {
|
||||||
|
return t.protoIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetReqResMatchers() []api.RequestResponseMatcher {
|
||||||
|
return t.reqResMatchers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsTapTarget() bool {
|
||||||
|
return t.isTapTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsClosed() bool {
|
||||||
|
return t.isClosed
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ go 1.17
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/beevik/etree v1.1.0
|
github.com/beevik/etree v1.1.0
|
||||||
|
github.com/mertyildiran/gqlparser/v2 v2.4.6
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||||
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -5,6 +6,13 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/mertyildiran/gqlparser/v2 v2.4.6 h1:enAq4F5PYgW/rYExPNzYt7IYrrZnzrfqdywMA1QdFtM=
|
||||||
|
github.com/mertyildiran/gqlparser/v2 v2.4.6/go.mod h1:XZId58F+XqRSmoLrdsOLgqA918oNvBzuOORruJWBjDo=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -18,8 +26,10 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
|
|||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
31
tap/extensions/http/graphql.go
Normal file
31
tap/extensions/http/graphql.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/mertyildiran/gqlparser/v2/ast"
|
||||||
|
"github.com/mertyildiran/gqlparser/v2/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isGraphQL(request map[string]interface{}) bool {
|
||||||
|
if postData, ok := request["postData"].(map[string]interface{}); ok {
|
||||||
|
if postData["mimeType"] == "application/json" {
|
||||||
|
if text, ok := postData["text"].(string); ok {
|
||||||
|
var data map[string]interface{}
|
||||||
|
if err := json.Unmarshal([]byte(text), &data); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if query, ok := data["query"].(string); ok {
|
||||||
|
|
||||||
|
_, err := parser.ParseQuery(&ast.Source{Name: "ff", Input: query})
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
@@ -47,7 +48,7 @@ func replaceForwardedFor(item *api.OutputChannelItem) {
|
|||||||
item.ConnectionInfo.ClientPort = ""
|
item.ConnectionInfo.ClientPort = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP2Stream(http2Assembler *Http2Assembler, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) error {
|
func handleHTTP2Stream(http2Assembler *Http2Assembler, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, captureTime time.Time, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) error {
|
||||||
streamID, messageHTTP1, isGrpc, err := http2Assembler.readMessage()
|
streamID, messageHTTP1, isGrpc, err := http2Assembler.readMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -66,7 +67,7 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, progress *api.ReadProgres
|
|||||||
streamID,
|
streamID,
|
||||||
"HTTP2",
|
"HTTP2",
|
||||||
)
|
)
|
||||||
item = reqResMatcher.registerRequest(ident, &messageHTTP1, superTimer.CaptureTime, progress.Current(), messageHTTP1.ProtoMinor)
|
item = reqResMatcher.registerRequest(ident, &messageHTTP1, captureTime, progress.Current(), messageHTTP1.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: tcpID.SrcIP,
|
||||||
@@ -86,7 +87,7 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, progress *api.ReadProgres
|
|||||||
streamID,
|
streamID,
|
||||||
"HTTP2",
|
"HTTP2",
|
||||||
)
|
)
|
||||||
item = reqResMatcher.registerResponse(ident, &messageHTTP1, superTimer.CaptureTime, progress.Current(), messageHTTP1.ProtoMinor)
|
item = reqResMatcher.registerResponse(ident, &messageHTTP1, captureTime, progress.Current(), messageHTTP1.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.DstIP,
|
ClientIP: tcpID.DstIP,
|
||||||
@@ -111,7 +112,7 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, progress *api.ReadProgres
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP1ClientStream(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, req *http.Request, err error) {
|
func handleHTTP1ClientStream(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, captureTime time.Time, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, req *http.Request, err error) {
|
||||||
req, err = http.ReadRequest(b)
|
req, err = http.ReadRequest(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -139,7 +140,7 @@ func handleHTTP1ClientStream(b *bufio.Reader, progress *api.ReadProgress, captur
|
|||||||
requestCounter,
|
requestCounter,
|
||||||
"HTTP1",
|
"HTTP1",
|
||||||
)
|
)
|
||||||
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, progress.Current(), req.ProtoMinor)
|
item := reqResMatcher.registerRequest(ident, req, captureTime, progress.Current(), req.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: tcpID.SrcIP,
|
||||||
@@ -154,7 +155,7 @@ func handleHTTP1ClientStream(b *bufio.Reader, progress *api.ReadProgress, captur
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP1ServerStream(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, err error) {
|
func handleHTTP1ServerStream(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, captureTime time.Time, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, err error) {
|
||||||
var res *http.Response
|
var res *http.Response
|
||||||
res, err = http.ReadResponse(b, nil)
|
res, err = http.ReadResponse(b, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -183,7 +184,7 @@ func handleHTTP1ServerStream(b *bufio.Reader, progress *api.ReadProgress, captur
|
|||||||
responseCounter,
|
responseCounter,
|
||||||
"HTTP1",
|
"HTTP1",
|
||||||
)
|
)
|
||||||
item := reqResMatcher.registerResponse(ident, res, superTimer.CaptureTime, progress.Current(), res.ProtoMinor)
|
item := reqResMatcher.registerResponse(ident, res, captureTime, progress.Current(), res.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.DstIP,
|
ClientIP: tcpID.DstIP,
|
||||||
|
|||||||
@@ -71,6 +71,34 @@ var grpcProtocol api.Protocol = api.Protocol{
|
|||||||
Priority: 0,
|
Priority: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var graphQL1Protocol api.Protocol = api.Protocol{
|
||||||
|
Name: "http",
|
||||||
|
LongName: "Hypertext Transfer Protocol -- HTTP/1.1 [ GraphQL over HTTP/1.1 ]",
|
||||||
|
Abbreviation: "GQL",
|
||||||
|
Macro: "gql",
|
||||||
|
Version: "1.1",
|
||||||
|
BackgroundColor: "#e10098",
|
||||||
|
ForegroundColor: "#ffffff",
|
||||||
|
FontSize: 12,
|
||||||
|
ReferenceLink: "https://graphql.org/learn/serving-over-http/",
|
||||||
|
Ports: []string{"80", "443", "8080"},
|
||||||
|
Priority: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
var graphQL2Protocol api.Protocol = api.Protocol{
|
||||||
|
Name: "http",
|
||||||
|
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ GraphQL over HTTP/2 ]",
|
||||||
|
Abbreviation: "GQL",
|
||||||
|
Macro: "gql",
|
||||||
|
Version: "2.0",
|
||||||
|
BackgroundColor: "#e10098",
|
||||||
|
ForegroundColor: "#ffffff",
|
||||||
|
FontSize: 12,
|
||||||
|
ReferenceLink: "https://graphql.org/learn/serving-over-http/",
|
||||||
|
Ports: []string{"80", "443", "8080", "50051"},
|
||||||
|
Priority: 0,
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TypeHttpRequest = iota
|
TypeHttpRequest = iota
|
||||||
TypeHttpResponse
|
TypeHttpResponse
|
||||||
@@ -86,15 +114,15 @@ func (d dissecting) Ping() {
|
|||||||
log.Printf("pong %s", http11protocol.Name)
|
log.Printf("pong %s", http11protocol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error {
|
||||||
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
reqResMatcher := reader.GetReqResMatcher().(*requestResponseMatcher)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
isHTTP2, _ := checkIsHTTP2Connection(b, isClient)
|
isHTTP2, _ := checkIsHTTP2Connection(b, reader.GetIsClient())
|
||||||
|
|
||||||
var http2Assembler *Http2Assembler
|
var http2Assembler *Http2Assembler
|
||||||
if isHTTP2 {
|
if isHTTP2 {
|
||||||
err = prepareHTTP2Connection(b, isClient)
|
err = prepareHTTP2Connection(b, reader.GetIsClient())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -105,74 +133,74 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
for {
|
for {
|
||||||
if switchingProtocolsHTTP2 {
|
if switchingProtocolsHTTP2 {
|
||||||
switchingProtocolsHTTP2 = false
|
switchingProtocolsHTTP2 = false
|
||||||
isHTTP2, err = checkIsHTTP2Connection(b, isClient)
|
isHTTP2, err = checkIsHTTP2Connection(b, reader.GetIsClient())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
err = prepareHTTP2Connection(b, isClient)
|
err = prepareHTTP2Connection(b, reader.GetIsClient())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
http2Assembler = createHTTP2Assembler(b)
|
http2Assembler = createHTTP2Assembler(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if superIdentifier.Protocol != nil && superIdentifier.Protocol != &http11protocol {
|
if reader.GetParent().GetProtoIdentifier().Protocol != nil && reader.GetParent().GetProtoIdentifier().Protocol != &http11protocol {
|
||||||
return errors.New("Identified by another protocol")
|
return errors.New("Identified by another protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
if isHTTP2 {
|
if isHTTP2 {
|
||||||
err = handleHTTP2Stream(http2Assembler, progress, capture, tcpID, superTimer, emitter, options, reqResMatcher)
|
err = handleHTTP2Stream(http2Assembler, reader.GetReadProgress(), reader.GetParent().GetOrigin(), reader.GetTcpID(), reader.GetCaptureTime(), reader.GetEmitter(), options, reqResMatcher)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &http11protocol
|
reader.GetParent().SetProtocol(&http11protocol)
|
||||||
} else if isClient {
|
} else if reader.GetIsClient() {
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
switchingProtocolsHTTP2, req, err = handleHTTP1ClientStream(b, progress, capture, tcpID, counterPair, superTimer, emitter, options, reqResMatcher)
|
switchingProtocolsHTTP2, req, err = handleHTTP1ClientStream(b, reader.GetReadProgress(), reader.GetParent().GetOrigin(), reader.GetTcpID(), reader.GetCounterPair(), reader.GetCaptureTime(), reader.GetEmitter(), options, reqResMatcher)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &http11protocol
|
reader.GetParent().SetProtocol(&http11protocol)
|
||||||
|
|
||||||
// In case of an HTTP2 upgrade, duplicate the HTTP1 request into HTTP2 with stream ID 1
|
// In case of an HTTP2 upgrade, duplicate the HTTP1 request into HTTP2 with stream ID 1
|
||||||
if switchingProtocolsHTTP2 {
|
if switchingProtocolsHTTP2 {
|
||||||
ident := fmt.Sprintf(
|
ident := fmt.Sprintf(
|
||||||
"%s_%s_%s_%s_1_%s",
|
"%s_%s_%s_%s_1_%s",
|
||||||
tcpID.SrcIP,
|
reader.GetTcpID().SrcIP,
|
||||||
tcpID.DstIP,
|
reader.GetTcpID().DstIP,
|
||||||
tcpID.SrcPort,
|
reader.GetTcpID().SrcPort,
|
||||||
tcpID.DstPort,
|
reader.GetTcpID().DstPort,
|
||||||
"HTTP2",
|
"HTTP2",
|
||||||
)
|
)
|
||||||
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, progress.Current(), req.ProtoMinor)
|
item := reqResMatcher.registerRequest(ident, req, reader.GetCaptureTime(), reader.GetReadProgress().Current(), req.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: reader.GetTcpID().SrcIP,
|
||||||
ClientPort: tcpID.SrcPort,
|
ClientPort: reader.GetTcpID().SrcPort,
|
||||||
ServerIP: tcpID.DstIP,
|
ServerIP: reader.GetTcpID().DstIP,
|
||||||
ServerPort: tcpID.DstPort,
|
ServerPort: reader.GetTcpID().DstPort,
|
||||||
IsOutgoing: true,
|
IsOutgoing: true,
|
||||||
}
|
}
|
||||||
item.Capture = capture
|
item.Capture = reader.GetParent().GetOrigin()
|
||||||
filterAndEmit(item, emitter, options)
|
filterAndEmit(item, reader.GetEmitter(), options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switchingProtocolsHTTP2, err = handleHTTP1ServerStream(b, progress, capture, tcpID, counterPair, superTimer, emitter, options, reqResMatcher)
|
switchingProtocolsHTTP2, err = handleHTTP1ServerStream(b, reader.GetReadProgress(), reader.GetParent().GetOrigin(), reader.GetTcpID(), reader.GetCounterPair(), reader.GetCaptureTime(), reader.GetEmitter(), options, reqResMatcher)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &http11protocol
|
reader.GetParent().SetProtocol(&http11protocol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if superIdentifier.Protocol == nil {
|
if reader.GetParent().GetProtoIdentifier().Protocol == nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +236,14 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isGraphQL(reqDetails) {
|
||||||
|
if item.Protocol.Version == "2.0" {
|
||||||
|
item.Protocol = graphQL2Protocol
|
||||||
|
} else {
|
||||||
|
item.Protocol = graphQL1Protocol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if resDetails["bodySize"].(float64) < 0 {
|
if resDetails["bodySize"].(float64) < 0 {
|
||||||
resDetails["bodySize"] = 0
|
resDetails["bodySize"] = 0
|
||||||
}
|
}
|
||||||
@@ -481,6 +517,7 @@ func (d dissecting) Macros() map[string]string {
|
|||||||
`http`: fmt.Sprintf(`proto.name == "%s" and proto.version.startsWith("%c")`, http11protocol.Name, http11protocol.Version[0]),
|
`http`: fmt.Sprintf(`proto.name == "%s" and proto.version.startsWith("%c")`, http11protocol.Name, http11protocol.Version[0]),
|
||||||
`http2`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, http11protocol.Name, http2Protocol.Version),
|
`http2`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, http11protocol.Name, http2Protocol.Version),
|
||||||
`grpc`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s" and proto.macro == "%s"`, http11protocol.Name, grpcProtocol.Version, grpcProtocol.Macro),
|
`grpc`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s" and proto.macro == "%s"`, http11protocol.Name, grpcProtocol.Version, grpcProtocol.Macro),
|
||||||
|
`gql`: fmt.Sprintf(`proto.name == "%s" and proto.macro == "%s"`, graphQL1Protocol.Name, graphQL1Protocol.Macro),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ func TestMacros(t *testing.T) {
|
|||||||
"http": `proto.name == "http" and proto.version.startsWith("1")`,
|
"http": `proto.name == "http" and proto.version.startsWith("1")`,
|
||||||
"http2": `proto.name == "http" and proto.version == "2.0"`,
|
"http2": `proto.name == "http" and proto.version == "2.0"`,
|
||||||
"grpc": `proto.name == "http" and proto.version == "2.0" and proto.macro == "grpc"`,
|
"grpc": `proto.name == "http" and proto.version == "2.0" and proto.macro == "grpc"`,
|
||||||
|
"gql": `proto.name == "http" and proto.macro == "gql"`,
|
||||||
}
|
}
|
||||||
dissector := NewDissector()
|
dissector := NewDissector()
|
||||||
macros := dissector.Macros()
|
macros := dissector.Macros()
|
||||||
@@ -108,7 +109,6 @@ func TestDissect(t *testing.T) {
|
|||||||
Request: 0,
|
Request: 0,
|
||||||
Response: 0,
|
Response: 0,
|
||||||
}
|
}
|
||||||
superIdentifier := &api.SuperIdentifier{}
|
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
pathClient := _path
|
pathClient := _path
|
||||||
@@ -124,7 +124,21 @@ func TestDissect(t *testing.T) {
|
|||||||
DstPort: "2",
|
DstPort: "2",
|
||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
stream := NewTcpStream(api.Pcap)
|
||||||
|
reader := NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDClient,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferClient, reader, options)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -142,7 +156,20 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
reader = NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDServer,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferServer, reader, options)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
84
tap/extensions/http/tcp_reader_mock_test.go
Normal file
84
tap/extensions/http/tcp_reader_mock_test.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpReader struct {
|
||||||
|
ident string
|
||||||
|
tcpID *api.TcpID
|
||||||
|
isClosed bool
|
||||||
|
isClient bool
|
||||||
|
isOutgoing bool
|
||||||
|
progress *api.ReadProgress
|
||||||
|
captureTime time.Time
|
||||||
|
parent api.TcpStream
|
||||||
|
extension *api.Extension
|
||||||
|
emitter api.Emitter
|
||||||
|
counterPair *api.CounterPair
|
||||||
|
reqResMatcher api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpReader(progress *api.ReadProgress, ident string, tcpId *api.TcpID, captureTime time.Time, parent api.TcpStream, isClient bool, isOutgoing bool, extension *api.Extension, emitter api.Emitter, counterPair *api.CounterPair, reqResMatcher api.RequestResponseMatcher) api.TcpReader {
|
||||||
|
return &tcpReader{
|
||||||
|
progress: progress,
|
||||||
|
ident: ident,
|
||||||
|
tcpID: tcpId,
|
||||||
|
captureTime: captureTime,
|
||||||
|
parent: parent,
|
||||||
|
isClient: isClient,
|
||||||
|
isOutgoing: isOutgoing,
|
||||||
|
extension: extension,
|
||||||
|
emitter: emitter,
|
||||||
|
counterPair: counterPair,
|
||||||
|
reqResMatcher: reqResMatcher,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) Read(p []byte) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReqResMatcher() api.RequestResponseMatcher {
|
||||||
|
return reader.reqResMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClient() bool {
|
||||||
|
return reader.isClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReadProgress() *api.ReadProgress {
|
||||||
|
return reader.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetParent() api.TcpStream {
|
||||||
|
return reader.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetTcpID() *api.TcpID {
|
||||||
|
return reader.tcpID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCounterPair() *api.CounterPair {
|
||||||
|
return reader.counterPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCaptureTime() time.Time {
|
||||||
|
return reader.captureTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetEmitter() api.Emitter {
|
||||||
|
return reader.emitter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClosed() bool {
|
||||||
|
return reader.isClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetExtension() *api.Extension {
|
||||||
|
return reader.extension
|
||||||
|
}
|
||||||
45
tap/extensions/http/tcp_stream_mock_test.go
Normal file
45
tap/extensions/http/tcp_stream_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpStream struct {
|
||||||
|
isClosed bool
|
||||||
|
protoIdentifier *api.ProtoIdentifier
|
||||||
|
isTapTarget bool
|
||||||
|
origin api.Capture
|
||||||
|
reqResMatchers []api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpStream(capture api.Capture) api.TcpStream {
|
||||||
|
return &tcpStream{
|
||||||
|
origin: capture,
|
||||||
|
protoIdentifier: &api.ProtoIdentifier{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) SetProtocol(protocol *api.Protocol) {}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetOrigin() api.Capture {
|
||||||
|
return t.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetProtoIdentifier() *api.ProtoIdentifier {
|
||||||
|
return t.protoIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetReqResMatchers() []api.RequestResponseMatcher {
|
||||||
|
return t.reqResMatchers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsTapTarget() bool {
|
||||||
|
return t.isTapTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsClosed() bool {
|
||||||
|
return t.isClosed
|
||||||
|
}
|
||||||
@@ -35,25 +35,25 @@ func (d dissecting) Ping() {
|
|||||||
log.Printf("pong %s", _protocol.Name)
|
log.Printf("pong %s", _protocol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error {
|
||||||
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
reqResMatcher := reader.GetReqResMatcher().(*requestResponseMatcher)
|
||||||
for {
|
for {
|
||||||
if superIdentifier.Protocol != nil && superIdentifier.Protocol != &_protocol {
|
if reader.GetParent().GetProtoIdentifier().Protocol != nil && reader.GetParent().GetProtoIdentifier().Protocol != &_protocol {
|
||||||
return errors.New("Identified by another protocol")
|
return errors.New("Identified by another protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
if isClient {
|
if reader.GetIsClient() {
|
||||||
_, _, err := ReadRequest(b, tcpID, counterPair, superTimer, reqResMatcher)
|
_, _, err := ReadRequest(b, reader.GetTcpID(), reader.GetCounterPair(), reader.GetCaptureTime(), reqResMatcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &_protocol
|
reader.GetParent().SetProtocol(&_protocol)
|
||||||
} else {
|
} else {
|
||||||
err := ReadResponse(b, capture, tcpID, counterPair, superTimer, emitter, reqResMatcher)
|
err := ReadResponse(b, reader.GetParent().GetOrigin(), reader.GetTcpID(), reader.GetCounterPair(), reader.GetCaptureTime(), reader.GetEmitter(), reqResMatcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &_protocol
|
reader.GetParent().SetProtocol(&_protocol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ func TestDissect(t *testing.T) {
|
|||||||
Request: 0,
|
Request: 0,
|
||||||
Response: 0,
|
Response: 0,
|
||||||
}
|
}
|
||||||
superIdentifier := &api.SuperIdentifier{}
|
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
pathClient := _path
|
pathClient := _path
|
||||||
@@ -123,7 +122,21 @@ func TestDissect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
reqResMatcher.SetMaxTry(10)
|
reqResMatcher.SetMaxTry(10)
|
||||||
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
stream := NewTcpStream(api.Pcap)
|
||||||
|
reader := NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDClient,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferClient, reader, options)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
@@ -141,7 +154,20 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
reader = NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDServer,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferServer, reader, options)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type Request struct {
|
|||||||
CaptureTime time.Time `json:"captureTime"`
|
CaptureTime time.Time `json:"captureTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadRequest(r io.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, reqResMatcher *requestResponseMatcher) (apiKey ApiKey, apiVersion int16, err error) {
|
func ReadRequest(r io.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, captureTime time.Time, reqResMatcher *requestResponseMatcher) (apiKey ApiKey, apiVersion int16, err error) {
|
||||||
d := &decoder{reader: r, remain: 4}
|
d := &decoder{reader: r, remain: 4}
|
||||||
size := d.readInt32()
|
size := d.readInt32()
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ func ReadRequest(r io.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, su
|
|||||||
ApiVersion: apiVersion,
|
ApiVersion: apiVersion,
|
||||||
CorrelationID: correlationID,
|
CorrelationID: correlationID,
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
CaptureTime: superTimer.CaptureTime,
|
CaptureTime: captureTime,
|
||||||
Payload: payload,
|
Payload: payload,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type Response struct {
|
|||||||
CaptureTime time.Time `json:"captureTime"`
|
CaptureTime time.Time `json:"captureTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadResponse(r io.Reader, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, reqResMatcher *requestResponseMatcher) (err error) {
|
func ReadResponse(r io.Reader, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, captureTime time.Time, emitter api.Emitter, reqResMatcher *requestResponseMatcher) (err error) {
|
||||||
d := &decoder{reader: r, remain: 4}
|
d := &decoder{reader: r, remain: 4}
|
||||||
size := d.readInt32()
|
size := d.readInt32()
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ func ReadResponse(r io.Reader, capture api.Capture, tcpID *api.TcpID, counterPai
|
|||||||
Size: size,
|
Size: size,
|
||||||
CorrelationID: correlationID,
|
CorrelationID: correlationID,
|
||||||
Payload: payload,
|
Payload: payload,
|
||||||
CaptureTime: superTimer.CaptureTime,
|
CaptureTime: captureTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
key := fmt.Sprintf(
|
key := fmt.Sprintf(
|
||||||
|
|||||||
84
tap/extensions/kafka/tcp_reader_mock_test.go
Normal file
84
tap/extensions/kafka/tcp_reader_mock_test.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package kafka
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpReader struct {
|
||||||
|
ident string
|
||||||
|
tcpID *api.TcpID
|
||||||
|
isClosed bool
|
||||||
|
isClient bool
|
||||||
|
isOutgoing bool
|
||||||
|
progress *api.ReadProgress
|
||||||
|
captureTime time.Time
|
||||||
|
parent api.TcpStream
|
||||||
|
extension *api.Extension
|
||||||
|
emitter api.Emitter
|
||||||
|
counterPair *api.CounterPair
|
||||||
|
reqResMatcher api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpReader(progress *api.ReadProgress, ident string, tcpId *api.TcpID, captureTime time.Time, parent api.TcpStream, isClient bool, isOutgoing bool, extension *api.Extension, emitter api.Emitter, counterPair *api.CounterPair, reqResMatcher api.RequestResponseMatcher) api.TcpReader {
|
||||||
|
return &tcpReader{
|
||||||
|
progress: progress,
|
||||||
|
ident: ident,
|
||||||
|
tcpID: tcpId,
|
||||||
|
captureTime: captureTime,
|
||||||
|
parent: parent,
|
||||||
|
isClient: isClient,
|
||||||
|
isOutgoing: isOutgoing,
|
||||||
|
extension: extension,
|
||||||
|
emitter: emitter,
|
||||||
|
counterPair: counterPair,
|
||||||
|
reqResMatcher: reqResMatcher,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) Read(p []byte) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReqResMatcher() api.RequestResponseMatcher {
|
||||||
|
return reader.reqResMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClient() bool {
|
||||||
|
return reader.isClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReadProgress() *api.ReadProgress {
|
||||||
|
return reader.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetParent() api.TcpStream {
|
||||||
|
return reader.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetTcpID() *api.TcpID {
|
||||||
|
return reader.tcpID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCounterPair() *api.CounterPair {
|
||||||
|
return reader.counterPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCaptureTime() time.Time {
|
||||||
|
return reader.captureTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetEmitter() api.Emitter {
|
||||||
|
return reader.emitter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClosed() bool {
|
||||||
|
return reader.isClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetExtension() *api.Extension {
|
||||||
|
return reader.extension
|
||||||
|
}
|
||||||
45
tap/extensions/kafka/tcp_stream_mock_test.go
Normal file
45
tap/extensions/kafka/tcp_stream_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package kafka
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpStream struct {
|
||||||
|
isClosed bool
|
||||||
|
protoIdentifier *api.ProtoIdentifier
|
||||||
|
isTapTarget bool
|
||||||
|
origin api.Capture
|
||||||
|
reqResMatchers []api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpStream(capture api.Capture) api.TcpStream {
|
||||||
|
return &tcpStream{
|
||||||
|
origin: capture,
|
||||||
|
protoIdentifier: &api.ProtoIdentifier{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) SetProtocol(protocol *api.Protocol) {}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetOrigin() api.Capture {
|
||||||
|
return t.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetProtoIdentifier() *api.ProtoIdentifier {
|
||||||
|
return t.protoIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetReqResMatchers() []api.RequestResponseMatcher {
|
||||||
|
return t.reqResMatchers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsTapTarget() bool {
|
||||||
|
return t.isTapTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsClosed() bool {
|
||||||
|
return t.isClosed
|
||||||
|
}
|
||||||
@@ -2,11 +2,12 @@ package redis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleClientStream(progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, request *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
func handleClientStream(progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, captureTime time.Time, emitter api.Emitter, request *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
||||||
counterPair.Lock()
|
counterPair.Lock()
|
||||||
counterPair.Request++
|
counterPair.Request++
|
||||||
requestCounter := counterPair.Request
|
requestCounter := counterPair.Request
|
||||||
@@ -21,7 +22,7 @@ func handleClientStream(progress *api.ReadProgress, capture api.Capture, tcpID *
|
|||||||
requestCounter,
|
requestCounter,
|
||||||
)
|
)
|
||||||
|
|
||||||
item := reqResMatcher.registerRequest(ident, request, superTimer.CaptureTime, progress.Current())
|
item := reqResMatcher.registerRequest(ident, request, captureTime, progress.Current())
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.Capture = capture
|
item.Capture = capture
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
@@ -36,7 +37,7 @@ func handleClientStream(progress *api.ReadProgress, capture api.Capture, tcpID *
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleServerStream(progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, response *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
func handleServerStream(progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, captureTime time.Time, emitter api.Emitter, response *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
||||||
counterPair.Lock()
|
counterPair.Lock()
|
||||||
counterPair.Response++
|
counterPair.Response++
|
||||||
responseCounter := counterPair.Response
|
responseCounter := counterPair.Response
|
||||||
@@ -51,7 +52,7 @@ func handleServerStream(progress *api.ReadProgress, capture api.Capture, tcpID *
|
|||||||
responseCounter,
|
responseCounter,
|
||||||
)
|
)
|
||||||
|
|
||||||
item := reqResMatcher.registerResponse(ident, response, superTimer.CaptureTime, progress.Current())
|
item := reqResMatcher.registerResponse(ident, response, captureTime, progress.Current())
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.Capture = capture
|
item.Capture = capture
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ func (d dissecting) Ping() {
|
|||||||
log.Printf("pong %s", protocol.Name)
|
log.Printf("pong %s", protocol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error {
|
||||||
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
reqResMatcher := reader.GetReqResMatcher().(*requestResponseMatcher)
|
||||||
is := &RedisInputStream{
|
is := &RedisInputStream{
|
||||||
Reader: b,
|
Reader: b,
|
||||||
Buf: make([]byte, 8192),
|
Buf: make([]byte, 8192),
|
||||||
@@ -47,10 +47,10 @@ func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isClient {
|
if reader.GetIsClient() {
|
||||||
err = handleClientStream(progress, capture, tcpID, counterPair, superTimer, emitter, redisPacket, reqResMatcher)
|
err = handleClientStream(reader.GetReadProgress(), reader.GetParent().GetOrigin(), reader.GetTcpID(), reader.GetCounterPair(), reader.GetCaptureTime(), reader.GetEmitter(), redisPacket, reqResMatcher)
|
||||||
} else {
|
} else {
|
||||||
err = handleServerStream(progress, capture, tcpID, counterPair, superTimer, emitter, redisPacket, reqResMatcher)
|
err = handleServerStream(reader.GetReadProgress(), reader.GetParent().GetOrigin(), reader.GetTcpID(), reader.GetCounterPair(), reader.GetCaptureTime(), reader.GetEmitter(), redisPacket, reqResMatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -107,7 +107,6 @@ func TestDissect(t *testing.T) {
|
|||||||
Request: 0,
|
Request: 0,
|
||||||
Response: 0,
|
Response: 0,
|
||||||
}
|
}
|
||||||
superIdentifier := &api.SuperIdentifier{}
|
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
pathClient := _path
|
pathClient := _path
|
||||||
@@ -123,7 +122,21 @@ func TestDissect(t *testing.T) {
|
|||||||
DstPort: "2",
|
DstPort: "2",
|
||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
stream := NewTcpStream(api.Pcap)
|
||||||
|
reader := NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDClient,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferClient, reader, options)
|
||||||
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
@@ -141,7 +154,20 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
reader = NewTcpReader(
|
||||||
|
&api.ReadProgress{},
|
||||||
|
"",
|
||||||
|
tcpIDServer,
|
||||||
|
time.Time{},
|
||||||
|
stream,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
)
|
||||||
|
err = dissector.Dissect(bufferServer, reader, options)
|
||||||
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|||||||
84
tap/extensions/redis/tcp_reader_mock_test.go
Normal file
84
tap/extensions/redis/tcp_reader_mock_test.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpReader struct {
|
||||||
|
ident string
|
||||||
|
tcpID *api.TcpID
|
||||||
|
isClosed bool
|
||||||
|
isClient bool
|
||||||
|
isOutgoing bool
|
||||||
|
progress *api.ReadProgress
|
||||||
|
captureTime time.Time
|
||||||
|
parent api.TcpStream
|
||||||
|
extension *api.Extension
|
||||||
|
emitter api.Emitter
|
||||||
|
counterPair *api.CounterPair
|
||||||
|
reqResMatcher api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpReader(progress *api.ReadProgress, ident string, tcpId *api.TcpID, captureTime time.Time, parent api.TcpStream, isClient bool, isOutgoing bool, extension *api.Extension, emitter api.Emitter, counterPair *api.CounterPair, reqResMatcher api.RequestResponseMatcher) api.TcpReader {
|
||||||
|
return &tcpReader{
|
||||||
|
progress: progress,
|
||||||
|
ident: ident,
|
||||||
|
tcpID: tcpId,
|
||||||
|
captureTime: captureTime,
|
||||||
|
parent: parent,
|
||||||
|
isClient: isClient,
|
||||||
|
isOutgoing: isOutgoing,
|
||||||
|
extension: extension,
|
||||||
|
emitter: emitter,
|
||||||
|
counterPair: counterPair,
|
||||||
|
reqResMatcher: reqResMatcher,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) Read(p []byte) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReqResMatcher() api.RequestResponseMatcher {
|
||||||
|
return reader.reqResMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClient() bool {
|
||||||
|
return reader.isClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReadProgress() *api.ReadProgress {
|
||||||
|
return reader.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetParent() api.TcpStream {
|
||||||
|
return reader.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetTcpID() *api.TcpID {
|
||||||
|
return reader.tcpID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCounterPair() *api.CounterPair {
|
||||||
|
return reader.counterPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCaptureTime() time.Time {
|
||||||
|
return reader.captureTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetEmitter() api.Emitter {
|
||||||
|
return reader.emitter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClosed() bool {
|
||||||
|
return reader.isClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetExtension() *api.Extension {
|
||||||
|
return reader.extension
|
||||||
|
}
|
||||||
45
tap/extensions/redis/tcp_stream_mock_test.go
Normal file
45
tap/extensions/redis/tcp_stream_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpStream struct {
|
||||||
|
isClosed bool
|
||||||
|
protoIdentifier *api.ProtoIdentifier
|
||||||
|
isTapTarget bool
|
||||||
|
origin api.Capture
|
||||||
|
reqResMatchers []api.RequestResponseMatcher
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpStream(capture api.Capture) api.TcpStream {
|
||||||
|
return &tcpStream{
|
||||||
|
origin: capture,
|
||||||
|
protoIdentifier: &api.ProtoIdentifier{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) SetProtocol(protocol *api.Protocol) {}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetOrigin() api.Capture {
|
||||||
|
return t.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetProtoIdentifier() *api.ProtoIdentifier {
|
||||||
|
return t.protoIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetReqResMatchers() []api.RequestResponseMatcher {
|
||||||
|
return t.reqResMatchers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsTapTarget() bool {
|
||||||
|
return t.isTapTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsClosed() bool {
|
||||||
|
return t.isClosed
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ require (
|
|||||||
github.com/go-errors/errors v1.4.2
|
github.com/go-errors/errors v1.4.2
|
||||||
github.com/google/gopacket v1.1.19
|
github.com/google/gopacket v1.1.19
|
||||||
github.com/up9inc/mizu/logger v0.0.0
|
github.com/up9inc/mizu/logger v0.0.0
|
||||||
github.com/up9inc/mizu/shared v0.0.0
|
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74
|
||||||
k8s.io/api v0.23.3
|
k8s.io/api v0.23.3
|
||||||
@@ -16,7 +15,6 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/go-logr/logr v1.2.2 // indirect
|
github.com/go-logr/logr v1.2.2 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
|
||||||
github.com/google/go-cmp v0.5.7 // indirect
|
github.com/google/go-cmp v0.5.7 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/martian v2.1.0+incompatible // indirect
|
github.com/google/martian v2.1.0+incompatible // indirect
|
||||||
@@ -29,16 +27,14 @@ require (
|
|||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
|
||||||
k8s.io/apimachinery v0.23.3 // indirect
|
k8s.io/apimachinery v0.23.3 // indirect
|
||||||
k8s.io/klog/v2 v2.40.1 // indirect
|
k8s.io/klog/v2 v2.40.1 // indirect
|
||||||
k8s.io/utils v0.0.0-20220127004650-9b3446523e65 // indirect
|
k8s.io/utils v0.0.0-20220127004650-9b3446523e65 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
|
replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/tap/api v0.0.0 => ./api
|
replace github.com/up9inc/mizu/tap/api v0.0.0 => ./api
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
|
||||||
|
|||||||
845
tap/go.sum
845
tap/go.sum
File diff suppressed because it is too large
Load Diff
@@ -69,10 +69,12 @@ func StartPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem,
|
|||||||
extensions = extensionsRef
|
extensions = extensionsRef
|
||||||
filteringOptions = options
|
filteringOptions = options
|
||||||
|
|
||||||
|
streamsMap := NewTcpStreamMap()
|
||||||
|
|
||||||
if *tls {
|
if *tls {
|
||||||
for _, e := range extensions {
|
for _, e := range extensions {
|
||||||
if e.Protocol.Name == "http" {
|
if e.Protocol.Name == "http" {
|
||||||
tlsTapperInstance = startTlsTapper(e, outputItems, options)
|
tlsTapperInstance = startTlsTapper(e, outputItems, options, streamsMap)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +84,7 @@ func StartPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem,
|
|||||||
diagnose.StartMemoryProfiler(os.Getenv(MemoryProfilingDumpPath), os.Getenv(MemoryProfilingTimeIntervalSeconds))
|
diagnose.StartMemoryProfiler(os.Getenv(MemoryProfilingDumpPath), os.Getenv(MemoryProfilingTimeIntervalSeconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
streamsMap, assembler := initializePassiveTapper(opts, outputItems)
|
assembler := initializePassiveTapper(opts, outputItems, streamsMap)
|
||||||
go startPassiveTapper(streamsMap, assembler)
|
go startPassiveTapper(streamsMap, assembler)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,9 +183,7 @@ func initializePacketSources() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializePassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem) (*tcpStreamMap, *tcpAssembler) {
|
func initializePassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem, streamsMap api.TcpStreamMap) *tcpAssembler {
|
||||||
streamsMap := NewTcpStreamMap()
|
|
||||||
|
|
||||||
diagnose.InitializeErrorsMap(*debug, *verbose, *quiet)
|
diagnose.InitializeErrorsMap(*debug, *verbose, *quiet)
|
||||||
diagnose.InitializeTapperInternalStats()
|
diagnose.InitializeTapperInternalStats()
|
||||||
|
|
||||||
@@ -195,11 +195,11 @@ func initializePassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelI
|
|||||||
|
|
||||||
assembler := NewTcpAssembler(outputItems, streamsMap, opts)
|
assembler := NewTcpAssembler(outputItems, streamsMap, opts)
|
||||||
|
|
||||||
return streamsMap, assembler
|
return assembler
|
||||||
}
|
}
|
||||||
|
|
||||||
func startPassiveTapper(streamsMap *tcpStreamMap, assembler *tcpAssembler) {
|
func startPassiveTapper(streamsMap api.TcpStreamMap, assembler *tcpAssembler) {
|
||||||
go streamsMap.closeTimedoutTcpStreamChannels()
|
go streamsMap.CloseTimedoutTcpStreamChannels()
|
||||||
|
|
||||||
diagnose.AppStats.SetStartTime(time.Now())
|
diagnose.AppStats.SetStartTime(time.Now())
|
||||||
|
|
||||||
@@ -232,7 +232,8 @@ func startPassiveTapper(streamsMap *tcpStreamMap, assembler *tcpAssembler) {
|
|||||||
logger.Log.Infof("AppStats: %v", diagnose.AppStats)
|
logger.Log.Infof("AppStats: %v", diagnose.AppStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChannelItem, options *api.TrafficFilteringOptions) *tlstapper.TlsTapper {
|
func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChannelItem,
|
||||||
|
options *api.TrafficFilteringOptions, streamsMap api.TcpStreamMap) *tlstapper.TlsTapper {
|
||||||
tls := tlstapper.TlsTapper{}
|
tls := tlstapper.TlsTapper{}
|
||||||
chunksBufferSize := os.Getpagesize() * 100
|
chunksBufferSize := os.Getpagesize() * 100
|
||||||
logBufferSize := os.Getpagesize()
|
logBufferSize := os.Getpagesize()
|
||||||
@@ -262,7 +263,7 @@ func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChanne
|
|||||||
}
|
}
|
||||||
|
|
||||||
go tls.PollForLogging()
|
go tls.PollForLogging()
|
||||||
go tls.Poll(emitter, options)
|
go tls.Poll(emitter, options, streamsMap)
|
||||||
|
|
||||||
return &tls
|
return &tls
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,24 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MemoryProfilingEnabledEnvVarName = "MEMORY_PROFILING_ENABLED"
|
MemoryProfilingEnabledEnvVarName = "MEMORY_PROFILING_ENABLED"
|
||||||
MemoryProfilingDumpPath = "MEMORY_PROFILING_DUMP_PATH"
|
MemoryProfilingDumpPath = "MEMORY_PROFILING_DUMP_PATH"
|
||||||
MemoryProfilingTimeIntervalSeconds = "MEMORY_PROFILING_TIME_INTERVAL"
|
MemoryProfilingTimeIntervalSeconds = "MEMORY_PROFILING_TIME_INTERVAL"
|
||||||
MaxBufferedPagesTotalEnvVarName = "MAX_BUFFERED_PAGES_TOTAL"
|
MaxBufferedPagesTotalEnvVarName = "MAX_BUFFERED_PAGES_TOTAL"
|
||||||
MaxBufferedPagesPerConnectionEnvVarName = "MAX_BUFFERED_PAGES_PER_CONNECTION"
|
MaxBufferedPagesPerConnectionEnvVarName = "MAX_BUFFERED_PAGES_PER_CONNECTION"
|
||||||
TcpStreamChannelTimeoutMsEnvVarName = "TCP_STREAM_CHANNEL_TIMEOUT_MS"
|
MaxBufferedPagesTotalDefaultValue = 5000
|
||||||
CloseTimedoutTcpChannelsIntervalMsEnvVar = "CLOSE_TIMEDOUT_TCP_STREAM_CHANNELS_INTERVAL_MS"
|
MaxBufferedPagesPerConnectionDefaultValue = 5000
|
||||||
MaxBufferedPagesTotalDefaultValue = 5000
|
TcpStreamChannelTimeoutMsEnvVarName = "TCP_STREAM_CHANNEL_TIMEOUT_MS"
|
||||||
MaxBufferedPagesPerConnectionDefaultValue = 5000
|
TcpStreamChannelTimeoutMsDefaultValue = 10000
|
||||||
TcpStreamChannelTimeoutMsDefaultValue = 10000
|
CloseTimedoutTcpChannelsIntervalMsEnvVarName = "CLOSE_TIMEDOUT_TCP_STREAM_CHANNELS_INTERVAL_MS"
|
||||||
|
CloseTimedoutTcpChannelsIntervalMsDefaultValue = 1000
|
||||||
|
CloseTimedoutTcpChannelsIntervalMsMinValue = 10
|
||||||
|
CloseTimedoutTcpChannelsIntervalMsMaxValue = 10000
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetMaxBufferedPagesTotal() int {
|
func GetMaxBufferedPagesTotal() int {
|
||||||
@@ -35,6 +40,10 @@ func GetMaxBufferedPagesPerConnection() int {
|
|||||||
return valueFromEnv
|
return valueFromEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMemoryProfilingEnabled() bool {
|
||||||
|
return os.Getenv(MemoryProfilingEnabledEnvVarName) == "1"
|
||||||
|
}
|
||||||
|
|
||||||
func GetTcpChannelTimeoutMs() time.Duration {
|
func GetTcpChannelTimeoutMs() time.Duration {
|
||||||
valueFromEnv, err := strconv.Atoi(os.Getenv(TcpStreamChannelTimeoutMsEnvVarName))
|
valueFromEnv, err := strconv.Atoi(os.Getenv(TcpStreamChannelTimeoutMsEnvVarName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -43,6 +52,25 @@ func GetTcpChannelTimeoutMs() time.Duration {
|
|||||||
return time.Duration(valueFromEnv) * time.Millisecond
|
return time.Duration(valueFromEnv) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMemoryProfilingEnabled() bool {
|
func GetCloseTimedoutTcpChannelsInterval() time.Duration {
|
||||||
return os.Getenv(MemoryProfilingEnabledEnvVarName) == "1"
|
defaultDuration := CloseTimedoutTcpChannelsIntervalMsDefaultValue * time.Millisecond
|
||||||
|
rangeMin := CloseTimedoutTcpChannelsIntervalMsMinValue
|
||||||
|
rangeMax := CloseTimedoutTcpChannelsIntervalMsMaxValue
|
||||||
|
closeTimedoutTcpChannelsIntervalMsStr := os.Getenv(CloseTimedoutTcpChannelsIntervalMsEnvVarName)
|
||||||
|
if closeTimedoutTcpChannelsIntervalMsStr == "" {
|
||||||
|
return defaultDuration
|
||||||
|
} else {
|
||||||
|
closeTimedoutTcpChannelsIntervalMs, err := strconv.Atoi(closeTimedoutTcpChannelsIntervalMsStr)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Warningf("Error parsing environment variable %s: %v\n", CloseTimedoutTcpChannelsIntervalMsEnvVarName, err)
|
||||||
|
return defaultDuration
|
||||||
|
} else {
|
||||||
|
if closeTimedoutTcpChannelsIntervalMs < rangeMin || closeTimedoutTcpChannelsIntervalMs > rangeMax {
|
||||||
|
logger.Log.Warningf("The value of environment variable %s is not in acceptable range: %d - %d\n", CloseTimedoutTcpChannelsIntervalMsEnvVarName, rangeMin, rangeMax)
|
||||||
|
return defaultDuration
|
||||||
|
} else {
|
||||||
|
return time.Duration(closeTimedoutTcpChannelsIntervalMs) * time.Millisecond
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func (c *context) GetCaptureInfo() gopacket.CaptureInfo {
|
|||||||
return c.CaptureInfo
|
return c.CaptureInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTcpAssembler(outputItems chan *api.OutputChannelItem, streamsMap *tcpStreamMap, opts *TapOpts) *tcpAssembler {
|
func NewTcpAssembler(outputItems chan *api.OutputChannelItem, streamsMap api.TcpStreamMap, opts *TapOpts) *tcpAssembler {
|
||||||
var emitter api.Emitter = &api.Emitting{
|
var emitter api.Emitter = &api.Emitting{
|
||||||
AppStats: &diagnose.AppStats,
|
AppStats: &diagnose.AppStats,
|
||||||
OutputChannel: outputItems,
|
OutputChannel: outputItems,
|
||||||
@@ -82,12 +82,6 @@ func (a *tcpAssembler) processPackets(dumpPacket bool, packets <-chan source.Tcp
|
|||||||
if tcp != nil {
|
if tcp != nil {
|
||||||
diagnose.AppStats.IncTcpPacketsCount()
|
diagnose.AppStats.IncTcpPacketsCount()
|
||||||
tcp := tcp.(*layers.TCP)
|
tcp := tcp.(*layers.TCP)
|
||||||
if *checksum {
|
|
||||||
err := tcp.SetNetworkLayerForChecksum(packet.NetworkLayer())
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Fatalf("Failed to set network layer for checksum: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c := context{
|
c := context{
|
||||||
CaptureInfo: packet.Metadata().CaptureInfo,
|
CaptureInfo: packet.Metadata().CaptureInfo,
|
||||||
|
|||||||
@@ -11,22 +11,9 @@ import (
|
|||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tcpReaderDataMsg struct {
|
/* TcpReader gets reads from a channel of bytes of tcp payload, and parses it into requests and responses.
|
||||||
bytes []byte
|
|
||||||
timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConnectionInfo struct {
|
|
||||||
ClientIP string
|
|
||||||
ClientPort string
|
|
||||||
ServerIP string
|
|
||||||
ServerPort string
|
|
||||||
IsOutgoing bool
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tcpReader gets reads from a channel of bytes of tcp payload, and parses it into requests and responses.
|
|
||||||
* The payload is written to the channel by a tcpStream object that is dedicated to one tcp connection.
|
* The payload is written to the channel by a tcpStream object that is dedicated to one tcp connection.
|
||||||
* An tcpReader object is unidirectional: it parses either a client stream or a server stream.
|
* An TcpReader object is unidirectional: it parses either a client stream or a server stream.
|
||||||
* Implements io.Reader interface (Read)
|
* Implements io.Reader interface (Read)
|
||||||
*/
|
*/
|
||||||
type tcpReader struct {
|
type tcpReader struct {
|
||||||
@@ -35,10 +22,10 @@ type tcpReader struct {
|
|||||||
isClosed bool
|
isClosed bool
|
||||||
isClient bool
|
isClient bool
|
||||||
isOutgoing bool
|
isOutgoing bool
|
||||||
msgQueue chan tcpReaderDataMsg // Channel of captured reassembled tcp payload
|
msgQueue chan api.TcpReaderDataMsg // Channel of captured reassembled tcp payload
|
||||||
data []byte
|
data []byte
|
||||||
progress *api.ReadProgress
|
progress *api.ReadProgress
|
||||||
superTimer *api.SuperTimer
|
captureTime time.Time
|
||||||
parent *tcpStream
|
parent *tcpStream
|
||||||
packetsSeen uint
|
packetsSeen uint
|
||||||
extension *api.Extension
|
extension *api.Extension
|
||||||
@@ -48,47 +35,114 @@ type tcpReader struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tcpReader) Read(p []byte) (int, error) {
|
func NewTcpReader(msgQueue chan api.TcpReaderDataMsg, progress *api.ReadProgress, ident string, tcpId *api.TcpID, captureTime time.Time, parent *tcpStream, isClient bool, isOutgoing bool, extension *api.Extension, emitter api.Emitter, counterPair *api.CounterPair, reqResMatcher api.RequestResponseMatcher) *tcpReader {
|
||||||
var msg tcpReaderDataMsg
|
return &tcpReader{
|
||||||
|
msgQueue: msgQueue,
|
||||||
ok := true
|
progress: progress,
|
||||||
for ok && len(h.data) == 0 {
|
ident: ident,
|
||||||
msg, ok = <-h.msgQueue
|
tcpID: tcpId,
|
||||||
h.data = msg.bytes
|
captureTime: captureTime,
|
||||||
|
parent: parent,
|
||||||
h.superTimer.CaptureTime = msg.timestamp
|
isClient: isClient,
|
||||||
if len(h.data) > 0 {
|
isOutgoing: isOutgoing,
|
||||||
h.packetsSeen += 1
|
extension: extension,
|
||||||
}
|
emitter: emitter,
|
||||||
|
counterPair: counterPair,
|
||||||
|
reqResMatcher: reqResMatcher,
|
||||||
}
|
}
|
||||||
if !ok || len(h.data) == 0 {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
l := copy(p, h.data)
|
|
||||||
h.data = h.data[l:]
|
|
||||||
h.progress.Feed(l)
|
|
||||||
|
|
||||||
return l, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tcpReader) Close() {
|
func (reader *tcpReader) run(options *api.TrafficFilteringOptions, wg *sync.WaitGroup) {
|
||||||
h.Lock()
|
|
||||||
if !h.isClosed {
|
|
||||||
h.isClosed = true
|
|
||||||
close(h.msgQueue)
|
|
||||||
}
|
|
||||||
h.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *tcpReader) run(wg *sync.WaitGroup) {
|
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
b := bufio.NewReader(h)
|
b := bufio.NewReader(reader)
|
||||||
err := h.extension.Dissector.Dissect(b, h.progress, h.parent.origin, h.isClient, h.tcpID, h.counterPair, h.superTimer, h.parent.superIdentifier, h.emitter, filteringOptions, h.reqResMatcher)
|
err := reader.extension.Dissector.Dissect(b, reader, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err = io.Copy(ioutil.Discard, b)
|
_, err = io.Copy(ioutil.Discard, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Errorf("%v", err)
|
logger.Log.Errorf("%v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) close() {
|
||||||
|
reader.Lock()
|
||||||
|
if !reader.isClosed {
|
||||||
|
reader.isClosed = true
|
||||||
|
close(reader.msgQueue)
|
||||||
|
}
|
||||||
|
reader.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) sendMsgIfNotClosed(msg api.TcpReaderDataMsg) {
|
||||||
|
reader.Lock()
|
||||||
|
if !reader.isClosed {
|
||||||
|
reader.msgQueue <- msg
|
||||||
|
}
|
||||||
|
reader.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) Read(p []byte) (int, error) {
|
||||||
|
var msg api.TcpReaderDataMsg
|
||||||
|
|
||||||
|
ok := true
|
||||||
|
for ok && len(reader.data) == 0 {
|
||||||
|
msg, ok = <-reader.msgQueue
|
||||||
|
if msg != nil {
|
||||||
|
reader.data = msg.GetBytes()
|
||||||
|
reader.captureTime = msg.GetTimestamp()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reader.data) > 0 {
|
||||||
|
reader.packetsSeen += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok || len(reader.data) == 0 {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
l := copy(p, reader.data)
|
||||||
|
reader.data = reader.data[l:]
|
||||||
|
reader.progress.Feed(l)
|
||||||
|
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReqResMatcher() api.RequestResponseMatcher {
|
||||||
|
return reader.reqResMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClient() bool {
|
||||||
|
return reader.isClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetReadProgress() *api.ReadProgress {
|
||||||
|
return reader.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetParent() api.TcpStream {
|
||||||
|
return reader.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetTcpID() *api.TcpID {
|
||||||
|
return reader.tcpID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCounterPair() *api.CounterPair {
|
||||||
|
return reader.counterPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetCaptureTime() time.Time {
|
||||||
|
return reader.captureTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetEmitter() api.Emitter {
|
||||||
|
return reader.emitter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetIsClosed() bool {
|
||||||
|
return reader.isClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reader *tcpReader) GetExtension() *api.Extension {
|
||||||
|
return reader.extension
|
||||||
|
}
|
||||||
|
|||||||
24
tap/tcp_reader_data_msg.go
Normal file
24
tap/tcp_reader_data_msg.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package tap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tcpReaderDataMsg struct {
|
||||||
|
bytes []byte
|
||||||
|
timestamp time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpReaderDataMsg(data []byte, timestamp time.Time) api.TcpReaderDataMsg {
|
||||||
|
return &tcpReaderDataMsg{data, timestamp}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dataMsg *tcpReaderDataMsg) GetBytes() []byte {
|
||||||
|
return dataMsg.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dataMsg *tcpReaderDataMsg) GetTimestamp() time.Time {
|
||||||
|
return dataMsg.timestamp
|
||||||
|
}
|
||||||
170
tap/tcp_reassembly_stream.go
Normal file
170
tap/tcp_reassembly_stream.go
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
package tap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/layers" // pulls in all layers decoders
|
||||||
|
"github.com/google/gopacket/reassembly"
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
"github.com/up9inc/mizu/tap/diagnose"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReassemblyStream interface {
|
||||||
|
Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool
|
||||||
|
ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext)
|
||||||
|
ReassemblyComplete(ac reassembly.AssemblerContext) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type tcpReassemblyStream struct {
|
||||||
|
ident string
|
||||||
|
tcpState *reassembly.TCPSimpleFSM
|
||||||
|
fsmerr bool
|
||||||
|
optchecker reassembly.TCPOptionCheck
|
||||||
|
isDNS bool
|
||||||
|
tcpStream api.TcpStream
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpReassemblyStream(ident string, tcp *layers.TCP, fsmOptions reassembly.TCPSimpleFSMOptions, stream api.TcpStream) ReassemblyStream {
|
||||||
|
return &tcpReassemblyStream{
|
||||||
|
ident: ident,
|
||||||
|
tcpState: reassembly.NewTCPSimpleFSM(fsmOptions),
|
||||||
|
optchecker: reassembly.NewTCPOptionCheck(),
|
||||||
|
isDNS: tcp.SrcPort == 53 || tcp.DstPort == 53,
|
||||||
|
tcpStream: stream,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpReassemblyStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool {
|
||||||
|
// FSM
|
||||||
|
if !t.tcpState.CheckState(tcp, dir) {
|
||||||
|
diagnose.TapErrors.SilentError("FSM-rejection", "%s: Packet rejected by FSM (state:%s)", t.ident, t.tcpState.String())
|
||||||
|
diagnose.InternalStats.RejectFsm++
|
||||||
|
if !t.fsmerr {
|
||||||
|
t.fsmerr = true
|
||||||
|
diagnose.InternalStats.RejectConnFsm++
|
||||||
|
}
|
||||||
|
if !*ignorefsmerr {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Options
|
||||||
|
err := t.optchecker.Accept(tcp, ci, dir, nextSeq, start)
|
||||||
|
if err != nil {
|
||||||
|
diagnose.TapErrors.SilentError("OptionChecker-rejection", "%s: Packet rejected by OptionChecker: %s", t.ident, err)
|
||||||
|
diagnose.InternalStats.RejectOpt++
|
||||||
|
if !*nooptcheck {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Checksum
|
||||||
|
accept := true
|
||||||
|
if *checksum {
|
||||||
|
c, err := tcp.ComputeChecksum()
|
||||||
|
if err != nil {
|
||||||
|
diagnose.TapErrors.SilentError("ChecksumCompute", "%s: Got error computing checksum: %s", t.ident, err)
|
||||||
|
accept = false
|
||||||
|
} else if c != 0x0 {
|
||||||
|
diagnose.TapErrors.SilentError("Checksum", "%s: Invalid checksum: 0x%x", t.ident, c)
|
||||||
|
accept = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !accept {
|
||||||
|
diagnose.InternalStats.RejectOpt++
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = true
|
||||||
|
|
||||||
|
return accept
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpReassemblyStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext) {
|
||||||
|
dir, _, _, skip := sg.Info()
|
||||||
|
length, saved := sg.Lengths()
|
||||||
|
// update stats
|
||||||
|
sgStats := sg.Stats()
|
||||||
|
if skip > 0 {
|
||||||
|
diagnose.InternalStats.MissedBytes += skip
|
||||||
|
}
|
||||||
|
diagnose.InternalStats.Sz += length - saved
|
||||||
|
diagnose.InternalStats.Pkt += sgStats.Packets
|
||||||
|
if sgStats.Chunks > 1 {
|
||||||
|
diagnose.InternalStats.Reassembled++
|
||||||
|
}
|
||||||
|
diagnose.InternalStats.OutOfOrderPackets += sgStats.QueuedPackets
|
||||||
|
diagnose.InternalStats.OutOfOrderBytes += sgStats.QueuedBytes
|
||||||
|
if length > diagnose.InternalStats.BiggestChunkBytes {
|
||||||
|
diagnose.InternalStats.BiggestChunkBytes = length
|
||||||
|
}
|
||||||
|
if sgStats.Packets > diagnose.InternalStats.BiggestChunkPackets {
|
||||||
|
diagnose.InternalStats.BiggestChunkPackets = sgStats.Packets
|
||||||
|
}
|
||||||
|
if sgStats.OverlapBytes != 0 && sgStats.OverlapPackets == 0 {
|
||||||
|
// In the original example this was handled with panic().
|
||||||
|
// I don't know what this error means or how to handle it properly.
|
||||||
|
diagnose.TapErrors.SilentError("Invalid-Overlap", "bytes:%d, pkts:%d", sgStats.OverlapBytes, sgStats.OverlapPackets)
|
||||||
|
}
|
||||||
|
diagnose.InternalStats.OverlapBytes += sgStats.OverlapBytes
|
||||||
|
diagnose.InternalStats.OverlapPackets += sgStats.OverlapPackets
|
||||||
|
|
||||||
|
if skip != -1 && skip != 0 {
|
||||||
|
// Missing bytes in stream: do not even try to parse it
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := sg.Fetch(length)
|
||||||
|
if t.isDNS {
|
||||||
|
dns := &layers.DNS{}
|
||||||
|
var decoded []gopacket.LayerType
|
||||||
|
if len(data) < 2 {
|
||||||
|
if len(data) > 0 {
|
||||||
|
sg.KeepFrom(0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dnsSize := binary.BigEndian.Uint16(data[:2])
|
||||||
|
missing := int(dnsSize) - len(data[2:])
|
||||||
|
diagnose.TapErrors.Debug("dnsSize: %d, missing: %d", dnsSize, missing)
|
||||||
|
if missing > 0 {
|
||||||
|
diagnose.TapErrors.Debug("Missing some bytes: %d", missing)
|
||||||
|
sg.KeepFrom(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p := gopacket.NewDecodingLayerParser(layers.LayerTypeDNS, dns)
|
||||||
|
err := p.DecodeLayers(data[2:], &decoded)
|
||||||
|
if err != nil {
|
||||||
|
diagnose.TapErrors.SilentError("DNS-parser", "Failed to decode DNS: %v", err)
|
||||||
|
} else {
|
||||||
|
diagnose.TapErrors.Debug("DNS: %s", gopacket.LayerDump(dns))
|
||||||
|
}
|
||||||
|
if len(data) > 2+int(dnsSize) {
|
||||||
|
sg.KeepFrom(2 + int(dnsSize))
|
||||||
|
}
|
||||||
|
} else if t.tcpStream.GetIsTapTarget() {
|
||||||
|
if length > 0 {
|
||||||
|
// This is where we pass the reassembled information onwards
|
||||||
|
// This channel is read by an tcpReader object
|
||||||
|
diagnose.AppStats.IncReassembledTcpPayloadsCount()
|
||||||
|
timestamp := ac.GetCaptureInfo().Timestamp
|
||||||
|
stream := t.tcpStream.(*tcpStream)
|
||||||
|
if dir == reassembly.TCPDirClientToServer {
|
||||||
|
for i := range stream.getClients() {
|
||||||
|
reader := stream.getClient(i)
|
||||||
|
reader.sendMsgIfNotClosed(NewTcpReaderDataMsg(data, timestamp))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := range stream.getServers() {
|
||||||
|
reader := stream.getServer(i)
|
||||||
|
reader.sendMsgIfNotClosed(NewTcpReaderDataMsg(data, timestamp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpReassemblyStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool {
|
||||||
|
if t.tcpStream.GetIsTapTarget() && !t.tcpStream.GetIsClosed() {
|
||||||
|
t.tcpStream.(*tcpStream).close()
|
||||||
|
}
|
||||||
|
// do not remove the connection to allow last ACK
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -1,202 +1,140 @@
|
|||||||
package tap
|
package tap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/gopacket"
|
|
||||||
"github.com/google/gopacket/layers" // pulls in all layers decoders
|
|
||||||
"github.com/google/gopacket/reassembly"
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
"github.com/up9inc/mizu/tap/diagnose"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/* It's a connection (bidirectional)
|
/* It's a connection (bidirectional)
|
||||||
* Implements gopacket.reassembly.Stream interface (Accept, ReassembledSG, ReassemblyComplete)
|
* Implements gopacket.reassembly.Stream interface (Accept, ReassembledSG, ReassemblyComplete)
|
||||||
* ReassembledSG gets called when new reassembled data is ready (i.e. bytes in order, no duplicates, complete)
|
* ReassembledSG gets called when new reassembled data is ready (i.e. bytes in order, no duplicates, complete)
|
||||||
* In our implementation, we pass information from ReassembledSG to the tcpReader through a shared channel.
|
* In our implementation, we pass information from ReassembledSG to the TcpReader through a shared channel.
|
||||||
*/
|
*/
|
||||||
type tcpStream struct {
|
type tcpStream struct {
|
||||||
id int64
|
id int64
|
||||||
isClosed bool
|
isClosed bool
|
||||||
superIdentifier *api.SuperIdentifier
|
protoIdentifier *api.ProtoIdentifier
|
||||||
tcpstate *reassembly.TCPSimpleFSM
|
|
||||||
fsmerr bool
|
|
||||||
optchecker reassembly.TCPOptionCheck
|
|
||||||
net, transport gopacket.Flow
|
|
||||||
isDNS bool
|
|
||||||
isTapTarget bool
|
isTapTarget bool
|
||||||
clients []tcpReader
|
clients []*tcpReader
|
||||||
servers []tcpReader
|
servers []*tcpReader
|
||||||
ident string
|
|
||||||
origin api.Capture
|
origin api.Capture
|
||||||
|
reqResMatchers []api.RequestResponseMatcher
|
||||||
|
createdAt time.Time
|
||||||
|
streamsMap api.TcpStreamMap
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
streamsMap *tcpStreamMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tcpStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool {
|
func NewTcpStream(isTapTarget bool, streamsMap api.TcpStreamMap, capture api.Capture) *tcpStream {
|
||||||
// FSM
|
return &tcpStream{
|
||||||
if !t.tcpstate.CheckState(tcp, dir) {
|
isTapTarget: isTapTarget,
|
||||||
diagnose.TapErrors.SilentError("FSM-rejection", "%s: Packet rejected by FSM (state:%s)", t.ident, t.tcpstate.String())
|
protoIdentifier: &api.ProtoIdentifier{},
|
||||||
diagnose.InternalStats.RejectFsm++
|
streamsMap: streamsMap,
|
||||||
if !t.fsmerr {
|
origin: capture,
|
||||||
t.fsmerr = true
|
|
||||||
diagnose.InternalStats.RejectConnFsm++
|
|
||||||
}
|
|
||||||
if !*ignorefsmerr {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Options
|
|
||||||
err := t.optchecker.Accept(tcp, ci, dir, nextSeq, start)
|
|
||||||
if err != nil {
|
|
||||||
diagnose.TapErrors.SilentError("OptionChecker-rejection", "%s: Packet rejected by OptionChecker: %s", t.ident, err)
|
|
||||||
diagnose.InternalStats.RejectOpt++
|
|
||||||
if !*nooptcheck {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Checksum
|
|
||||||
accept := true
|
|
||||||
if *checksum {
|
|
||||||
c, err := tcp.ComputeChecksum()
|
|
||||||
if err != nil {
|
|
||||||
diagnose.TapErrors.SilentError("ChecksumCompute", "%s: Got error computing checksum: %s", t.ident, err)
|
|
||||||
accept = false
|
|
||||||
} else if c != 0x0 {
|
|
||||||
diagnose.TapErrors.SilentError("Checksum", "%s: Invalid checksum: 0x%x", t.ident, c)
|
|
||||||
accept = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !accept {
|
|
||||||
diagnose.InternalStats.RejectOpt++
|
|
||||||
}
|
|
||||||
|
|
||||||
*start = true
|
|
||||||
|
|
||||||
return accept
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext) {
|
|
||||||
dir, _, _, skip := sg.Info()
|
|
||||||
length, saved := sg.Lengths()
|
|
||||||
// update stats
|
|
||||||
sgStats := sg.Stats()
|
|
||||||
if skip > 0 {
|
|
||||||
diagnose.InternalStats.MissedBytes += skip
|
|
||||||
}
|
|
||||||
diagnose.InternalStats.Sz += length - saved
|
|
||||||
diagnose.InternalStats.Pkt += sgStats.Packets
|
|
||||||
if sgStats.Chunks > 1 {
|
|
||||||
diagnose.InternalStats.Reassembled++
|
|
||||||
}
|
|
||||||
diagnose.InternalStats.OutOfOrderPackets += sgStats.QueuedPackets
|
|
||||||
diagnose.InternalStats.OutOfOrderBytes += sgStats.QueuedBytes
|
|
||||||
if length > diagnose.InternalStats.BiggestChunkBytes {
|
|
||||||
diagnose.InternalStats.BiggestChunkBytes = length
|
|
||||||
}
|
|
||||||
if sgStats.Packets > diagnose.InternalStats.BiggestChunkPackets {
|
|
||||||
diagnose.InternalStats.BiggestChunkPackets = sgStats.Packets
|
|
||||||
}
|
|
||||||
if sgStats.OverlapBytes != 0 && sgStats.OverlapPackets == 0 {
|
|
||||||
// In the original example this was handled with panic().
|
|
||||||
// I don't know what this error means or how to handle it properly.
|
|
||||||
diagnose.TapErrors.SilentError("Invalid-Overlap", "bytes:%d, pkts:%d", sgStats.OverlapBytes, sgStats.OverlapPackets)
|
|
||||||
}
|
|
||||||
diagnose.InternalStats.OverlapBytes += sgStats.OverlapBytes
|
|
||||||
diagnose.InternalStats.OverlapPackets += sgStats.OverlapPackets
|
|
||||||
|
|
||||||
if skip == -1 && *allowmissinginit {
|
|
||||||
// this is allowed
|
|
||||||
} else if skip != 0 {
|
|
||||||
// Missing bytes in stream: do not even try to parse it
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data := sg.Fetch(length)
|
|
||||||
if t.isDNS {
|
|
||||||
dns := &layers.DNS{}
|
|
||||||
var decoded []gopacket.LayerType
|
|
||||||
if len(data) < 2 {
|
|
||||||
if len(data) > 0 {
|
|
||||||
sg.KeepFrom(0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dnsSize := binary.BigEndian.Uint16(data[:2])
|
|
||||||
missing := int(dnsSize) - len(data[2:])
|
|
||||||
diagnose.TapErrors.Debug("dnsSize: %d, missing: %d", dnsSize, missing)
|
|
||||||
if missing > 0 {
|
|
||||||
diagnose.TapErrors.Debug("Missing some bytes: %d", missing)
|
|
||||||
sg.KeepFrom(0)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p := gopacket.NewDecodingLayerParser(layers.LayerTypeDNS, dns)
|
|
||||||
err := p.DecodeLayers(data[2:], &decoded)
|
|
||||||
if err != nil {
|
|
||||||
diagnose.TapErrors.SilentError("DNS-parser", "Failed to decode DNS: %v", err)
|
|
||||||
} else {
|
|
||||||
diagnose.TapErrors.Debug("DNS: %s", gopacket.LayerDump(dns))
|
|
||||||
}
|
|
||||||
if len(data) > 2+int(dnsSize) {
|
|
||||||
sg.KeepFrom(2 + int(dnsSize))
|
|
||||||
}
|
|
||||||
} else if t.isTapTarget {
|
|
||||||
if length > 0 {
|
|
||||||
// This is where we pass the reassembled information onwards
|
|
||||||
// This channel is read by an tcpReader object
|
|
||||||
diagnose.AppStats.IncReassembledTcpPayloadsCount()
|
|
||||||
timestamp := ac.GetCaptureInfo().Timestamp
|
|
||||||
if dir == reassembly.TCPDirClientToServer {
|
|
||||||
for i := range t.clients {
|
|
||||||
reader := &t.clients[i]
|
|
||||||
reader.Lock()
|
|
||||||
if !reader.isClosed {
|
|
||||||
reader.msgQueue <- tcpReaderDataMsg{data, timestamp}
|
|
||||||
}
|
|
||||||
reader.Unlock()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i := range t.servers {
|
|
||||||
reader := &t.servers[i]
|
|
||||||
reader.Lock()
|
|
||||||
if !reader.isClosed {
|
|
||||||
reader.msgQueue <- tcpReaderDataMsg{data, timestamp}
|
|
||||||
}
|
|
||||||
reader.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tcpStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool {
|
func (t *tcpStream) getId() int64 {
|
||||||
if t.isTapTarget && !t.isClosed {
|
return t.id
|
||||||
t.Close()
|
|
||||||
}
|
|
||||||
// do not remove the connection to allow last ACK
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tcpStream) Close() {
|
func (t *tcpStream) setId(id int64) {
|
||||||
shouldReturn := false
|
t.id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) close() {
|
||||||
t.Lock()
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
if t.isClosed {
|
if t.isClosed {
|
||||||
shouldReturn = true
|
|
||||||
} else {
|
|
||||||
t.isClosed = true
|
|
||||||
}
|
|
||||||
t.Unlock()
|
|
||||||
if shouldReturn {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.isClosed = true
|
||||||
|
|
||||||
t.streamsMap.Delete(t.id)
|
t.streamsMap.Delete(t.id)
|
||||||
|
|
||||||
for i := range t.clients {
|
for i := range t.clients {
|
||||||
reader := &t.clients[i]
|
reader := t.clients[i]
|
||||||
reader.Close()
|
reader.close()
|
||||||
}
|
}
|
||||||
for i := range t.servers {
|
for i := range t.servers {
|
||||||
reader := &t.servers[i]
|
reader := t.servers[i]
|
||||||
reader.Close()
|
reader.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) addClient(reader *tcpReader) {
|
||||||
|
t.clients = append(t.clients, reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) addServer(reader *tcpReader) {
|
||||||
|
t.servers = append(t.servers, reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) getClients() []*tcpReader {
|
||||||
|
return t.clients
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) getServers() []*tcpReader {
|
||||||
|
return t.servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) getClient(index int) *tcpReader {
|
||||||
|
return t.clients[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) getServer(index int) *tcpReader {
|
||||||
|
return t.servers[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) addReqResMatcher(reqResMatcher api.RequestResponseMatcher) {
|
||||||
|
t.reqResMatchers = append(t.reqResMatchers, reqResMatcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) SetProtocol(protocol *api.Protocol) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
if t.protoIdentifier.IsClosedOthers {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.protoIdentifier.Protocol = protocol
|
||||||
|
|
||||||
|
for i := range t.clients {
|
||||||
|
reader := t.clients[i]
|
||||||
|
if reader.GetExtension().Protocol != t.protoIdentifier.Protocol {
|
||||||
|
reader.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range t.servers {
|
||||||
|
reader := t.servers[i]
|
||||||
|
if reader.GetExtension().Protocol != t.protoIdentifier.Protocol {
|
||||||
|
reader.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.protoIdentifier.IsClosedOthers = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetOrigin() api.Capture {
|
||||||
|
return t.origin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetProtoIdentifier() *api.ProtoIdentifier {
|
||||||
|
return t.protoIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetReqResMatchers() []api.RequestResponseMatcher {
|
||||||
|
return t.reqResMatchers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsTapTarget() bool {
|
||||||
|
return t.isTapTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tcpStream) GetIsClosed() bool {
|
||||||
|
return t.isClosed
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,19 +21,13 @@ import (
|
|||||||
*/
|
*/
|
||||||
type tcpStreamFactory struct {
|
type tcpStreamFactory struct {
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
Emitter api.Emitter
|
emitter api.Emitter
|
||||||
streamsMap *tcpStreamMap
|
streamsMap api.TcpStreamMap
|
||||||
ownIps []string
|
ownIps []string
|
||||||
opts *TapOpts
|
opts *TapOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpStreamWrapper struct {
|
func NewTcpStreamFactory(emitter api.Emitter, streamsMap api.TcpStreamMap, opts *TapOpts) *tcpStreamFactory {
|
||||||
stream *tcpStream
|
|
||||||
reqResMatcher api.RequestResponseMatcher
|
|
||||||
createdAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTcpStreamFactory(emitter api.Emitter, streamsMap *tcpStreamMap, opts *TapOpts) *tcpStreamFactory {
|
|
||||||
var ownIps []string
|
var ownIps []string
|
||||||
|
|
||||||
if localhostIPs, err := getLocalhostIPs(); err != nil {
|
if localhostIPs, err := getLocalhostIPs(); err != nil {
|
||||||
@@ -46,14 +40,14 @@ func NewTcpStreamFactory(emitter api.Emitter, streamsMap *tcpStreamMap, opts *Ta
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &tcpStreamFactory{
|
return &tcpStreamFactory{
|
||||||
Emitter: emitter,
|
emitter: emitter,
|
||||||
streamsMap: streamsMap,
|
streamsMap: streamsMap,
|
||||||
ownIps: ownIps,
|
ownIps: ownIps,
|
||||||
opts: opts,
|
opts: opts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.TCP, ac reassembly.AssemblerContext) reassembly.Stream {
|
func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcpLayer *layers.TCP, ac reassembly.AssemblerContext) reassembly.Stream {
|
||||||
fsmOptions := reassembly.TCPSimpleFSMOptions{
|
fsmOptions := reassembly.TCPSimpleFSMOptions{
|
||||||
SupportMissingEstablishment: *allowmissinginit,
|
SupportMissingEstablishment: *allowmissinginit,
|
||||||
}
|
}
|
||||||
@@ -64,78 +58,68 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T
|
|||||||
|
|
||||||
props := factory.getStreamProps(srcIp, srcPort, dstIp, dstPort)
|
props := factory.getStreamProps(srcIp, srcPort, dstIp, dstPort)
|
||||||
isTapTarget := props.isTapTarget
|
isTapTarget := props.isTapTarget
|
||||||
stream := &tcpStream{
|
stream := NewTcpStream(isTapTarget, factory.streamsMap, getPacketOrigin(ac))
|
||||||
net: net,
|
reassemblyStream := NewTcpReassemblyStream(fmt.Sprintf("%s:%s", net, transport), tcpLayer, fsmOptions, stream)
|
||||||
transport: transport,
|
if stream.GetIsTapTarget() {
|
||||||
isDNS: tcp.SrcPort == 53 || tcp.DstPort == 53,
|
stream.setId(factory.streamsMap.NextId())
|
||||||
isTapTarget: isTapTarget,
|
|
||||||
tcpstate: reassembly.NewTCPSimpleFSM(fsmOptions),
|
|
||||||
ident: fmt.Sprintf("%s:%s", net, transport),
|
|
||||||
optchecker: reassembly.NewTCPOptionCheck(),
|
|
||||||
superIdentifier: &api.SuperIdentifier{},
|
|
||||||
streamsMap: factory.streamsMap,
|
|
||||||
origin: getPacketOrigin(ac),
|
|
||||||
}
|
|
||||||
if stream.isTapTarget {
|
|
||||||
stream.id = factory.streamsMap.nextId()
|
|
||||||
for i, extension := range extensions {
|
for i, extension := range extensions {
|
||||||
reqResMatcher := extension.Dissector.NewResponseRequestMatcher()
|
reqResMatcher := extension.Dissector.NewResponseRequestMatcher()
|
||||||
|
stream.addReqResMatcher(reqResMatcher)
|
||||||
counterPair := &api.CounterPair{
|
counterPair := &api.CounterPair{
|
||||||
Request: 0,
|
Request: 0,
|
||||||
Response: 0,
|
Response: 0,
|
||||||
}
|
}
|
||||||
stream.clients = append(stream.clients, tcpReader{
|
stream.addClient(
|
||||||
msgQueue: make(chan tcpReaderDataMsg),
|
NewTcpReader(
|
||||||
progress: &api.ReadProgress{},
|
make(chan api.TcpReaderDataMsg),
|
||||||
superTimer: &api.SuperTimer{},
|
&api.ReadProgress{},
|
||||||
ident: fmt.Sprintf("%s %s", net, transport),
|
fmt.Sprintf("%s %s", net, transport),
|
||||||
tcpID: &api.TcpID{
|
&api.TcpID{
|
||||||
SrcIP: srcIp,
|
SrcIP: srcIp,
|
||||||
DstIP: dstIp,
|
DstIP: dstIp,
|
||||||
SrcPort: srcPort,
|
SrcPort: srcPort,
|
||||||
DstPort: dstPort,
|
DstPort: dstPort,
|
||||||
},
|
},
|
||||||
parent: stream,
|
time.Time{},
|
||||||
isClient: true,
|
stream,
|
||||||
isOutgoing: props.isOutgoing,
|
true,
|
||||||
extension: extension,
|
props.isOutgoing,
|
||||||
emitter: factory.Emitter,
|
extension,
|
||||||
counterPair: counterPair,
|
factory.emitter,
|
||||||
reqResMatcher: reqResMatcher,
|
counterPair,
|
||||||
})
|
reqResMatcher,
|
||||||
stream.servers = append(stream.servers, tcpReader{
|
),
|
||||||
msgQueue: make(chan tcpReaderDataMsg),
|
)
|
||||||
progress: &api.ReadProgress{},
|
stream.addServer(
|
||||||
superTimer: &api.SuperTimer{},
|
NewTcpReader(
|
||||||
ident: fmt.Sprintf("%s %s", net, transport),
|
make(chan api.TcpReaderDataMsg),
|
||||||
tcpID: &api.TcpID{
|
&api.ReadProgress{},
|
||||||
SrcIP: net.Dst().String(),
|
fmt.Sprintf("%s %s", net, transport),
|
||||||
DstIP: net.Src().String(),
|
&api.TcpID{
|
||||||
SrcPort: transport.Dst().String(),
|
SrcIP: net.Dst().String(),
|
||||||
DstPort: transport.Src().String(),
|
DstIP: net.Src().String(),
|
||||||
},
|
SrcPort: transport.Dst().String(),
|
||||||
parent: stream,
|
DstPort: transport.Src().String(),
|
||||||
isClient: false,
|
},
|
||||||
isOutgoing: props.isOutgoing,
|
time.Time{},
|
||||||
extension: extension,
|
stream,
|
||||||
emitter: factory.Emitter,
|
false,
|
||||||
counterPair: counterPair,
|
props.isOutgoing,
|
||||||
reqResMatcher: reqResMatcher,
|
extension,
|
||||||
})
|
factory.emitter,
|
||||||
|
counterPair,
|
||||||
|
reqResMatcher,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
factory.streamsMap.Store(stream.id, &tcpStreamWrapper{
|
factory.streamsMap.Store(stream.getId(), stream)
|
||||||
stream: stream,
|
|
||||||
reqResMatcher: reqResMatcher,
|
|
||||||
createdAt: time.Now(),
|
|
||||||
})
|
|
||||||
|
|
||||||
factory.wg.Add(2)
|
factory.wg.Add(2)
|
||||||
// Start reading from channel stream.reader.bytes
|
go stream.getClient(i).run(filteringOptions, &factory.wg)
|
||||||
go stream.clients[i].run(&factory.wg)
|
go stream.getServer(i).run(filteringOptions, &factory.wg)
|
||||||
go stream.servers[i].run(&factory.wg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stream
|
return reassemblyStream
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *tcpStreamFactory) WaitGoRoutines() {
|
func (factory *tcpStreamFactory) WaitGoRoutines() {
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
package tap
|
package tap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
_debug "runtime/debug"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
"github.com/up9inc/mizu/tap/diagnose"
|
"github.com/up9inc/mizu/tap/diagnose"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,12 +15,16 @@ type tcpStreamMap struct {
|
|||||||
streamId int64
|
streamId int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTcpStreamMap() *tcpStreamMap {
|
func NewTcpStreamMap() api.TcpStreamMap {
|
||||||
return &tcpStreamMap{
|
return &tcpStreamMap{
|
||||||
streams: &sync.Map{},
|
streams: &sync.Map{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (streamMap *tcpStreamMap) Range(f func(key, value interface{}) bool) {
|
||||||
|
streamMap.streams.Range(f)
|
||||||
|
}
|
||||||
|
|
||||||
func (streamMap *tcpStreamMap) Store(key, value interface{}) {
|
func (streamMap *tcpStreamMap) Store(key, value interface{}) {
|
||||||
streamMap.streams.Store(key, value)
|
streamMap.streams.Store(key, value)
|
||||||
}
|
}
|
||||||
@@ -31,66 +33,34 @@ func (streamMap *tcpStreamMap) Delete(key interface{}) {
|
|||||||
streamMap.streams.Delete(key)
|
streamMap.streams.Delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (streamMap *tcpStreamMap) nextId() int64 {
|
func (streamMap *tcpStreamMap) NextId() int64 {
|
||||||
streamMap.streamId++
|
streamMap.streamId++
|
||||||
return streamMap.streamId
|
return streamMap.streamId
|
||||||
}
|
}
|
||||||
|
|
||||||
func (streamMap *tcpStreamMap) getCloseTimedoutTcpChannelsInterval() time.Duration {
|
func (streamMap *tcpStreamMap) CloseTimedoutTcpStreamChannels() {
|
||||||
defaultDuration := 1000 * time.Millisecond
|
tcpStreamChannelTimeoutMs := GetTcpChannelTimeoutMs()
|
||||||
rangeMin := 10
|
closeTimedoutTcpChannelsIntervalMs := GetCloseTimedoutTcpChannelsInterval()
|
||||||
rangeMax := 10000
|
|
||||||
closeTimedoutTcpChannelsIntervalMsStr := os.Getenv(CloseTimedoutTcpChannelsIntervalMsEnvVar)
|
|
||||||
if closeTimedoutTcpChannelsIntervalMsStr == "" {
|
|
||||||
return defaultDuration
|
|
||||||
} else {
|
|
||||||
closeTimedoutTcpChannelsIntervalMs, err := strconv.Atoi(closeTimedoutTcpChannelsIntervalMsStr)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Warningf("Error parsing environment variable %s: %v\n", CloseTimedoutTcpChannelsIntervalMsEnvVar, err)
|
|
||||||
return defaultDuration
|
|
||||||
} else {
|
|
||||||
if closeTimedoutTcpChannelsIntervalMs < rangeMin || closeTimedoutTcpChannelsIntervalMs > rangeMax {
|
|
||||||
logger.Log.Warningf("The value of environment variable %s is not in acceptable range: %d - %d\n", CloseTimedoutTcpChannelsIntervalMsEnvVar, rangeMin, rangeMax)
|
|
||||||
return defaultDuration
|
|
||||||
} else {
|
|
||||||
return time.Duration(closeTimedoutTcpChannelsIntervalMs) * time.Millisecond
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (streamMap *tcpStreamMap) closeTimedoutTcpStreamChannels() {
|
|
||||||
tcpStreamChannelTimeout := GetTcpChannelTimeoutMs()
|
|
||||||
closeTimedoutTcpChannelsIntervalMs := streamMap.getCloseTimedoutTcpChannelsInterval()
|
|
||||||
logger.Log.Infof("Using %d ms as the close timedout TCP stream channels interval", closeTimedoutTcpChannelsIntervalMs/time.Millisecond)
|
logger.Log.Infof("Using %d ms as the close timedout TCP stream channels interval", closeTimedoutTcpChannelsIntervalMs/time.Millisecond)
|
||||||
|
|
||||||
|
ticker := time.NewTicker(closeTimedoutTcpChannelsIntervalMs)
|
||||||
for {
|
for {
|
||||||
time.Sleep(closeTimedoutTcpChannelsIntervalMs)
|
<-ticker.C
|
||||||
_debug.FreeOSMemory()
|
|
||||||
streamMap.streams.Range(func(key interface{}, value interface{}) bool {
|
streamMap.streams.Range(func(key interface{}, value interface{}) bool {
|
||||||
streamWrapper := value.(*tcpStreamWrapper)
|
// `*tlsStream` is not yet applicable to this routine.
|
||||||
stream := streamWrapper.stream
|
// So, we cast into `(*tcpStream)` and ignore `*tlsStream`
|
||||||
if stream.superIdentifier.Protocol == nil {
|
stream, ok := value.(*tcpStream)
|
||||||
if !stream.isClosed && time.Now().After(streamWrapper.createdAt.Add(tcpStreamChannelTimeout)) {
|
if !ok {
|
||||||
stream.Close()
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream.protoIdentifier.Protocol == nil {
|
||||||
|
if !stream.isClosed && time.Now().After(stream.createdAt.Add(tcpStreamChannelTimeoutMs)) {
|
||||||
|
stream.close()
|
||||||
diagnose.AppStats.IncDroppedTcpStreams()
|
diagnose.AppStats.IncDroppedTcpStreams()
|
||||||
logger.Log.Debugf("Dropped an unidentified TCP stream because of timeout. Total dropped: %d Total Goroutines: %d Timeout (ms): %d",
|
logger.Log.Debugf("Dropped an unidentified TCP stream because of timeout. Total dropped: %d Total Goroutines: %d Timeout (ms): %d",
|
||||||
diagnose.AppStats.DroppedTcpStreams, runtime.NumGoroutine(), tcpStreamChannelTimeout/time.Millisecond)
|
diagnose.AppStats.DroppedTcpStreams, runtime.NumGoroutine(), tcpStreamChannelTimeoutMs/time.Millisecond)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !stream.superIdentifier.IsClosedOthers {
|
|
||||||
for i := range stream.clients {
|
|
||||||
reader := &stream.clients[i]
|
|
||||||
if reader.extension.Protocol != stream.superIdentifier.Protocol {
|
|
||||||
reader.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := range stream.servers {
|
|
||||||
reader := &stream.servers[i]
|
|
||||||
if reader.extension.Protocol != stream.superIdentifier.Protocol {
|
|
||||||
reader.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.superIdentifier.IsClosedOthers = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ const FLAGS_IS_READ_BIT uint32 = (1 << 1)
|
|||||||
// Be careful when editing, alignment and padding should be exactly the same in go/c.
|
// Be careful when editing, alignment and padding should be exactly the same in go/c.
|
||||||
//
|
//
|
||||||
type tlsChunk struct {
|
type tlsChunk struct {
|
||||||
Pid uint32 // process id
|
Pid uint32 // process id
|
||||||
Tgid uint32 // thread id inside the process
|
Tgid uint32 // thread id inside the process
|
||||||
Len uint32 // the size of the native buffer used to read/write the tls data (may be bigger than tlsChunk.Data[])
|
Len uint32 // the size of the native buffer used to read/write the tls data (may be bigger than tlsChunk.Data[])
|
||||||
Start uint32 // the start offset withing the native buffer
|
Start uint32 // the start offset withing the native buffer
|
||||||
Recorded uint32 // number of bytes copied from the native buffer to tlsChunk.Data[]
|
Recorded uint32 // number of bytes copied from the native buffer to tlsChunk.Data[]
|
||||||
Fd uint32 // the file descriptor used to read/write the tls data (probably socket file descriptor)
|
Fd uint32 // the file descriptor used to read/write the tls data (probably socket file descriptor)
|
||||||
Flags uint32 // bitwise flags
|
Flags uint32 // bitwise flags
|
||||||
Address [16]byte // ipv4 address and port
|
Address [16]byte // ipv4 address and port
|
||||||
Data [4096]byte // actual tls data
|
Data [4096]byte // actual tls data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func (p *tlsPoller) close() error {
|
|||||||
return p.chunksReader.Close()
|
return p.chunksReader.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *tlsPoller) poll(emitter api.Emitter, options *api.TrafficFilteringOptions) {
|
func (p *tlsPoller) poll(emitter api.Emitter, options *api.TrafficFilteringOptions, streamsMap api.TcpStreamMap) {
|
||||||
chunks := make(chan *tlsChunk)
|
chunks := make(chan *tlsChunk)
|
||||||
|
|
||||||
go p.pollChunksPerfBuffer(chunks)
|
go p.pollChunksPerfBuffer(chunks)
|
||||||
@@ -71,7 +71,7 @@ func (p *tlsPoller) poll(emitter api.Emitter, options *api.TrafficFilteringOptio
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.handleTlsChunk(chunk, p.extension, emitter, options); err != nil {
|
if err := p.handleTlsChunk(chunk, p.extension, emitter, options, streamsMap); err != nil {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
}
|
}
|
||||||
case key := <-p.closedReaders:
|
case key := <-p.closedReaders:
|
||||||
@@ -115,8 +115,8 @@ func (p *tlsPoller) pollChunksPerfBuffer(chunks chan<- *tlsChunk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *tlsPoller) handleTlsChunk(chunk *tlsChunk, extension *api.Extension,
|
func (p *tlsPoller) handleTlsChunk(chunk *tlsChunk, extension *api.Extension, emitter api.Emitter,
|
||||||
emitter api.Emitter, options *api.TrafficFilteringOptions) error {
|
options *api.TrafficFilteringOptions, streamsMap api.TcpStreamMap) error {
|
||||||
ip, port, err := chunk.getAddress()
|
ip, port, err := chunk.getAddress()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -127,11 +127,11 @@ func (p *tlsPoller) handleTlsChunk(chunk *tlsChunk, extension *api.Extension,
|
|||||||
reader, exists := p.readers[key]
|
reader, exists := p.readers[key]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
reader = p.startNewTlsReader(chunk, ip, port, key, extension, emitter, options)
|
reader = p.startNewTlsReader(chunk, ip, port, key, emitter, extension, options, streamsMap)
|
||||||
p.readers[key] = reader
|
p.readers[key] = reader
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.timer.CaptureTime = time.Now()
|
reader.captureTime = time.Now()
|
||||||
reader.chunks <- chunk
|
reader.chunks <- chunk
|
||||||
|
|
||||||
if os.Getenv("MIZU_VERBOSE_TLS_TAPPER") == "true" {
|
if os.Getenv("MIZU_VERBOSE_TLS_TAPPER") == "true" {
|
||||||
@@ -141,41 +141,54 @@ func (p *tlsPoller) handleTlsChunk(chunk *tlsChunk, extension *api.Extension,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *tlsPoller) startNewTlsReader(chunk *tlsChunk, ip net.IP, port uint16, key string, extension *api.Extension,
|
func (p *tlsPoller) startNewTlsReader(chunk *tlsChunk, ip net.IP, port uint16, key string,
|
||||||
emitter api.Emitter, options *api.TrafficFilteringOptions) *tlsReader {
|
emitter api.Emitter, extension *api.Extension, options *api.TrafficFilteringOptions,
|
||||||
|
streamsMap api.TcpStreamMap) *tlsReader {
|
||||||
reader := &tlsReader{
|
|
||||||
key: key,
|
|
||||||
chunks: make(chan *tlsChunk, 1),
|
|
||||||
doneHandler: func(r *tlsReader) {
|
|
||||||
p.closeReader(key, r)
|
|
||||||
},
|
|
||||||
progress: &api.ReadProgress{},
|
|
||||||
timer: api.SuperTimer{
|
|
||||||
CaptureTime: time.Now(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tcpid := p.buildTcpId(chunk, ip, port)
|
tcpid := p.buildTcpId(chunk, ip, port)
|
||||||
|
|
||||||
|
doneHandler := func(r *tlsReader) {
|
||||||
|
p.closeReader(key, r)
|
||||||
|
}
|
||||||
|
|
||||||
tlsEmitter := &tlsEmitter{
|
tlsEmitter := &tlsEmitter{
|
||||||
delegate: emitter,
|
delegate: emitter,
|
||||||
namespace: p.getNamespace(chunk.Pid),
|
namespace: p.getNamespace(chunk.Pid),
|
||||||
}
|
}
|
||||||
|
|
||||||
go dissect(extension, reader, chunk.isRequest(), &tcpid, tlsEmitter, options, p.reqResMatcher)
|
reader := &tlsReader{
|
||||||
|
key: key,
|
||||||
|
chunks: make(chan *tlsChunk, 1),
|
||||||
|
doneHandler: doneHandler,
|
||||||
|
progress: &api.ReadProgress{},
|
||||||
|
tcpID: &tcpid,
|
||||||
|
isClient: chunk.isRequest(),
|
||||||
|
captureTime: time.Now(),
|
||||||
|
extension: extension,
|
||||||
|
emitter: tlsEmitter,
|
||||||
|
counterPair: &api.CounterPair{},
|
||||||
|
reqResMatcher: p.reqResMatcher,
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := &tlsStream{
|
||||||
|
reader: reader,
|
||||||
|
protoIdentifier: &api.ProtoIdentifier{},
|
||||||
|
}
|
||||||
|
streamsMap.Store(streamsMap.NextId(), stream)
|
||||||
|
|
||||||
|
reader.parent = stream
|
||||||
|
|
||||||
|
go dissect(extension, reader, options)
|
||||||
return reader
|
return reader
|
||||||
}
|
}
|
||||||
|
|
||||||
func dissect(extension *api.Extension, reader *tlsReader, isRequest bool, tcpid *api.TcpID,
|
func dissect(extension *api.Extension, reader *tlsReader, options *api.TrafficFilteringOptions) {
|
||||||
tlsEmitter *tlsEmitter, options *api.TrafficFilteringOptions, reqResMatcher api.RequestResponseMatcher) {
|
|
||||||
b := bufio.NewReader(reader)
|
b := bufio.NewReader(reader)
|
||||||
|
|
||||||
err := extension.Dissector.Dissect(b, reader.progress, api.Ebpf, isRequest, tcpid, &api.CounterPair{},
|
err := extension.Dissector.Dissect(b, reader, options)
|
||||||
&reader.timer, &api.SuperIdentifier{}, tlsEmitter, options, reqResMatcher)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Warningf("Error dissecting TLS %v - %v", tcpid, err)
|
logger.Log.Warningf("Error dissecting TLS %v - %v", reader.GetTcpID(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type tlsReader struct {
|
type tlsReader struct {
|
||||||
key string
|
key string
|
||||||
chunks chan *tlsChunk
|
chunks chan *tlsChunk
|
||||||
data []byte
|
data []byte
|
||||||
doneHandler func(r *tlsReader)
|
doneHandler func(r *tlsReader)
|
||||||
progress *api.ReadProgress
|
progress *api.ReadProgress
|
||||||
timer api.SuperTimer
|
tcpID *api.TcpID
|
||||||
|
isClient bool
|
||||||
|
captureTime time.Time
|
||||||
|
extension *api.Extension
|
||||||
|
emitter api.Emitter
|
||||||
|
counterPair *api.CounterPair
|
||||||
|
parent *tlsStream
|
||||||
|
reqResMatcher api.RequestResponseMatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *tlsReader) Read(p []byte) (int, error) {
|
func (r *tlsReader) Read(p []byte) (int, error) {
|
||||||
@@ -44,3 +51,43 @@ func (r *tlsReader) Read(p []byte) (int, error) {
|
|||||||
|
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetReqResMatcher() api.RequestResponseMatcher {
|
||||||
|
return r.reqResMatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetIsClient() bool {
|
||||||
|
return r.isClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetReadProgress() *api.ReadProgress {
|
||||||
|
return r.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetParent() api.TcpStream {
|
||||||
|
return r.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetTcpID() *api.TcpID {
|
||||||
|
return r.tcpID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetCounterPair() *api.CounterPair {
|
||||||
|
return r.counterPair
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetCaptureTime() time.Time {
|
||||||
|
return r.captureTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetEmitter() api.Emitter {
|
||||||
|
return r.emitter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetIsClosed() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *tlsReader) GetExtension() *api.Extension {
|
||||||
|
return r.extension
|
||||||
|
}
|
||||||
|
|||||||
32
tap/tlstapper/tls_stream.go
Normal file
32
tap/tlstapper/tls_stream.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package tlstapper
|
||||||
|
|
||||||
|
import "github.com/up9inc/mizu/tap/api"
|
||||||
|
|
||||||
|
type tlsStream struct {
|
||||||
|
reader *tlsReader
|
||||||
|
protoIdentifier *api.ProtoIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tlsStream) GetOrigin() api.Capture {
|
||||||
|
return api.Ebpf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tlsStream) GetProtoIdentifier() *api.ProtoIdentifier {
|
||||||
|
return t.protoIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tlsStream) SetProtocol(protocol *api.Protocol) {
|
||||||
|
t.protoIdentifier.Protocol = protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tlsStream) GetReqResMatchers() []api.RequestResponseMatcher {
|
||||||
|
return []api.RequestResponseMatcher{t.reader.reqResMatcher}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tlsStream) GetIsTapTarget() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tlsStream) GetIsClosed() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -50,8 +50,8 @@ func (t *TlsTapper) Init(chunksBufferSize int, logBufferSize int, procfs string,
|
|||||||
return t.poller.init(&t.bpfObjects, chunksBufferSize)
|
return t.poller.init(&t.bpfObjects, chunksBufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TlsTapper) Poll(emitter api.Emitter, options *api.TrafficFilteringOptions) {
|
func (t *TlsTapper) Poll(emitter api.Emitter, options *api.TrafficFilteringOptions, streamsMap api.TcpStreamMap) {
|
||||||
t.poller.poll(emitter, options)
|
t.poller.poll(emitter, options, streamsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TlsTapper) PollForLogging() {
|
func (t *TlsTapper) PollForLogging() {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
src/
|
|
||||||
node_modules/
|
node_modules/
|
||||||
.snapshots/
|
.snapshots/
|
||||||
*.min.js
|
*.min.js
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"extends": [
|
|
||||||
"standard",
|
|
||||||
"standard-react",
|
|
||||||
"plugin:prettier/recommended",
|
|
||||||
"prettier/standard",
|
|
||||||
"prettier/react",
|
|
||||||
"plugin:@typescript-eslint/eslint-recommended"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2020,
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"legacyDecorators": true,
|
|
||||||
"jsx": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"react": {
|
|
||||||
"version": "16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"space-before-function-paren": 0,
|
|
||||||
"react/prop-types": 0,
|
|
||||||
"react/jsx-handler-names": 0,
|
|
||||||
"react/jsx-fragments": 0,
|
|
||||||
"react/no-unused-prop-types": 0,
|
|
||||||
"import/export": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
ui-common/package-lock.json
generated
14
ui-common/package-lock.json
generated
@@ -23,7 +23,7 @@
|
|||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"node-fetch": "^3.1.1",
|
"node-fetch": "^3.1.1",
|
||||||
"numeral": "^2.0.6",
|
"numeral": "^2.0.6",
|
||||||
"protobuf-decoder": "^0.1.0",
|
"protobuf-decoder": "^0.1.2",
|
||||||
"react-graph-vis": "^1.0.7",
|
"react-graph-vis": "^1.0.7",
|
||||||
"react-lowlight": "^3.0.0",
|
"react-lowlight": "^3.0.0",
|
||||||
"react-router-dom": "^6.2.1",
|
"react-router-dom": "^6.2.1",
|
||||||
@@ -26065,9 +26065,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/protobuf-decoder": {
|
"node_modules/protobuf-decoder": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/protobuf-decoder/-/protobuf-decoder-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/protobuf-decoder/-/protobuf-decoder-0.1.2.tgz",
|
||||||
"integrity": "sha512-yeyeCkdvOnzv+6/2YNx2FlT7565arz/mb0QnhmXFdHMwnek9Jp/0PpHJVdJkzdFBgi85XQWRcHdWHh2dOBrSng=="
|
"integrity": "sha512-dKPIsI7W1A88f8WAXHzNujQuDWLAWVviw2svDOlwkpdVlaV8TRjxuBL4tE3dczYWRZ1ZeNts06k9njB4xjnBVQ=="
|
||||||
},
|
},
|
||||||
"node_modules/proxy-addr": {
|
"node_modules/proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
@@ -55355,9 +55355,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"protobuf-decoder": {
|
"protobuf-decoder": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/protobuf-decoder/-/protobuf-decoder-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/protobuf-decoder/-/protobuf-decoder-0.1.2.tgz",
|
||||||
"integrity": "sha512-yeyeCkdvOnzv+6/2YNx2FlT7565arz/mb0QnhmXFdHMwnek9Jp/0PpHJVdJkzdFBgi85XQWRcHdWHh2dOBrSng=="
|
"integrity": "sha512-dKPIsI7W1A88f8WAXHzNujQuDWLAWVviw2svDOlwkpdVlaV8TRjxuBL4tE3dczYWRZ1ZeNts06k9njB4xjnBVQ=="
|
||||||
},
|
},
|
||||||
"proxy-addr": {
|
"proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
"test:build": "run-s build",
|
"test:build": "run-s build",
|
||||||
"test:lint": "eslint .",
|
"test:lint": "eslint .",
|
||||||
"predeploy": "cd example && npm install && npm run build",
|
"predeploy": "cd example && npm install && npm run build",
|
||||||
"deploy": "gh-pages -d example/build"
|
"deploy": "gh-pages -d example/build",
|
||||||
|
"eslint": "eslint . --ext .js,.jsx,.ts,.tsx"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@craco/craco": "^6.4.3",
|
"@craco/craco": "^6.4.3",
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
overflow-y: scroll
|
overflow-y: scroll
|
||||||
|
|
||||||
.borderLine
|
.borderLine
|
||||||
border-top: 1px solid #dee6fe
|
border-top: 1px solid #dee6fe
|
||||||
margin-bottom: 1%
|
margin-bottom: 1%
|
||||||
|
|
||||||
|
.root
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Box, Fade, FormControl, MenuItem, Modal, Backdrop } from "@material-ui/core";
|
import { Box, Fade, FormControl, MenuItem, Modal, Backdrop } from "@material-ui/core";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { RedocStandalone } from "redoc";
|
import { RedocStandalone } from "redoc";
|
||||||
import closeIcon from "assets/closeIcon.svg";
|
import closeIcon from "assets/closeIcon.svg";
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
@@ -7,8 +7,8 @@ import style from './OasModal.module.sass';
|
|||||||
import openApiLogo from 'assets/openApiLogo.png'
|
import openApiLogo from 'assets/openApiLogo.png'
|
||||||
import { redocThemeOptions } from "./redocThemeOptions";
|
import { redocThemeOptions } from "./redocThemeOptions";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Select } from "../UI/Select";
|
|
||||||
import { TOAST_CONTAINER_ID } from "../../configs/Consts";
|
import { TOAST_CONTAINER_ID } from "../../configs/Consts";
|
||||||
|
import SearchableDropdown from "../UI/SearchableDropdown/SearchableDropdown";
|
||||||
|
|
||||||
|
|
||||||
const modalStyle = {
|
const modalStyle = {
|
||||||
@@ -30,6 +30,8 @@ const OasModal = ({ openModal, handleCloseModal, getOasServices, getOasByService
|
|||||||
const [oasServices, setOasServices] = useState([] as string[])
|
const [oasServices, setOasServices] = useState([] as string[])
|
||||||
const [selectedServiceName, setSelectedServiceName] = useState("");
|
const [selectedServiceName, setSelectedServiceName] = useState("");
|
||||||
const [selectedServiceSpec, setSelectedServiceSpec] = useState(null);
|
const [selectedServiceSpec, setSelectedServiceSpec] = useState(null);
|
||||||
|
|
||||||
|
const classes = {root: style.root}
|
||||||
|
|
||||||
const onSelectedOASService = async (selectedService) => {
|
const onSelectedOASService = async (selectedService) => {
|
||||||
if (oasServices.length === 0) {
|
if (oasServices.length === 0) {
|
||||||
@@ -88,19 +90,12 @@ const OasModal = ({ openModal, handleCloseModal, getOasServices, getOasByService
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.selectContainer} >
|
<div className={style.selectContainer} >
|
||||||
<FormControl>
|
<FormControl classes={classes}>
|
||||||
<Select
|
<SearchableDropdown
|
||||||
labelId="service-select-label"
|
options={oasServices}
|
||||||
id="service-select"
|
selectedValues={selectedServiceName}
|
||||||
value={selectedServiceName}
|
onChange={onSelectedOASService}
|
||||||
onChangeCb={onSelectedOASService}
|
/>
|
||||||
>
|
|
||||||
{oasServices.map((service) => (
|
|
||||||
<MenuItem key={service} value={service}>
|
|
||||||
{service}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.borderLine}></div>
|
<div className={style.borderLine}></div>
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const protocols = [
|
|||||||
{ key: "HTTP", value: "HTTP", component: <LegentLabel color="#205cf5" name="HTTP" /> },
|
{ key: "HTTP", value: "HTTP", component: <LegentLabel color="#205cf5" name="HTTP" /> },
|
||||||
{ key: "HTTP/2", value: "HTTP/2", component: <LegentLabel color='#244c5a' name="HTTP/2" /> },
|
{ key: "HTTP/2", value: "HTTP/2", component: <LegentLabel color='#244c5a' name="HTTP/2" /> },
|
||||||
{ key: "gRPC", value: "gRPC", component: <LegentLabel color='#244c5a' name="gRPC" /> },
|
{ key: "gRPC", value: "gRPC", component: <LegentLabel color='#244c5a' name="gRPC" /> },
|
||||||
|
{ key: "GQL", value: "GQL", component: <LegentLabel color='#e10098' name="GQL" /> },
|
||||||
{ key: "AMQP", value: "AMQP", component: <LegentLabel color='#ff6600' name="AMQP" /> },
|
{ key: "AMQP", value: "AMQP", component: <LegentLabel color='#ff6600' name="AMQP" /> },
|
||||||
{ key: "KAFKA", value: "KAFKA", component: <LegentLabel color='#000000' name="KAFKA" /> },
|
{ key: "KAFKA", value: "KAFKA", component: <LegentLabel color='#000000' name="KAFKA" /> },
|
||||||
{ key: "REDIS", value: "REDIS", component: <LegentLabel color='#a41e11' name="REDIS" /> },]
|
{ key: "REDIS", value: "REDIS", component: <LegentLabel color='#a41e11' name="REDIS" /> },]
|
||||||
|
|||||||
@@ -158,9 +158,10 @@ export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
|
|||||||
return jsonBeautify(protobufDecoded, null, 2, 80);
|
return jsonBeautify(protobufDecoded, null, 2, 80);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if(isDecodeGrpc)
|
if (String(error).includes("More than one message in")){
|
||||||
|
if(isDecodeGrpc)
|
||||||
setIsDecodeGrpc(false);
|
setIsDecodeGrpc(false);
|
||||||
if (!String(error).includes("More than one message in")){
|
} else {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99999 13.6568L9.99997 13.6569L5.75732 9.41421L7.17154 8L10.0001 10.8285L12.8285 8.00009L14.2428 9.41431L10.0001 13.6569L9.99999 13.6568Z" fill="#205CF5"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 310 B |
@@ -0,0 +1,30 @@
|
|||||||
|
.optionItem
|
||||||
|
font-size: 12px
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
overflow: hidden
|
||||||
|
text-overflow: ellipsis
|
||||||
|
white-space: nowrap
|
||||||
|
font-family: Source Sans Pro, Lucida Grande, Tahoma, sans-serif
|
||||||
|
|
||||||
|
.title
|
||||||
|
overflow: hidden
|
||||||
|
text-overflow: ellipsis
|
||||||
|
white-space: nowrap
|
||||||
|
font-family: Source Sans Pro, Lucida Grande, Tahoma, sans-serif
|
||||||
|
|
||||||
|
.optionListItem
|
||||||
|
font-size: 12px
|
||||||
|
margin-right: -15px
|
||||||
|
background-color: #262a3e
|
||||||
|
border-radius: 20px 0px 0px 20px
|
||||||
|
padding: 0px 16px 4px 12px
|
||||||
|
display: flex
|
||||||
|
max-width: 100px
|
||||||
|
height: 18px
|
||||||
|
|
||||||
|
.optionListItemTitle
|
||||||
|
overflow: hidden
|
||||||
|
max-width: 80px
|
||||||
|
text-overflow: ellipsis
|
||||||
|
white-space: nowrap
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import { Autocomplete } from "@material-ui/lab";
|
||||||
|
import { Checkbox, TextField } from "@material-ui/core";
|
||||||
|
import CheckBoxOutlineBlankIcon from "@material-ui/icons/CheckBoxOutlineBlank";
|
||||||
|
import CheckBoxIcon from "@material-ui/icons/CheckBox";
|
||||||
|
import DefaultIconDown from "DefaultIconDown.svg";
|
||||||
|
import styles from "./SearchableDropdown.module.sass";
|
||||||
|
|
||||||
|
interface SearchableDropdownProps {
|
||||||
|
options: string[],
|
||||||
|
selectedValues?: any,
|
||||||
|
onChange: (string) => void,
|
||||||
|
isLoading?: boolean,
|
||||||
|
label?: string,
|
||||||
|
multiple?: boolean,
|
||||||
|
inputWidth?: string
|
||||||
|
freeSolo?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(() => ({
|
||||||
|
|
||||||
|
inputRoot: {
|
||||||
|
padding: "8px 4px 8px 12px !important",
|
||||||
|
borderRadius: "9px !important"
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
padding: "0px 33px 0px 0px !important",
|
||||||
|
height: 18,
|
||||||
|
fontWeight: "normal",
|
||||||
|
fontFamily: "Source Sans Pro, Lucida Grande, Tahoma, sans-serif"
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
"& .MuiFormLabel-root": {
|
||||||
|
fontFamily: "Source Sans Pro, Lucida Grande, Tahoma, sans-serif"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
const SearchableDropdown: React.FC<SearchableDropdownProps> = ({ options, selectedValues, onChange, isLoading, label, multiple, inputWidth, freeSolo }) => {
|
||||||
|
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return <Autocomplete
|
||||||
|
freeSolo={freeSolo}
|
||||||
|
multiple={multiple}
|
||||||
|
loading={isLoading}
|
||||||
|
classes={classes}
|
||||||
|
options={options ? options : []}
|
||||||
|
disableCloseOnSelect={multiple}
|
||||||
|
fullWidth={false}
|
||||||
|
disableClearable
|
||||||
|
value={selectedValues ? selectedValues : (multiple ? [] : null)}
|
||||||
|
getOptionLabel={(option) => option}
|
||||||
|
onChange={(event, val) => onChange(val)}
|
||||||
|
size={"small"}
|
||||||
|
popupIcon={<img style={{ padding: 7 }} alt="iconDown" src={DefaultIconDown} />}
|
||||||
|
renderOption={(option, { selected }) => (
|
||||||
|
<div id={`option-${option}`} className={styles.optionItem}>
|
||||||
|
{multiple && <Checkbox
|
||||||
|
icon={<CheckBoxOutlineBlankIcon fontSize="small" />}
|
||||||
|
checkedIcon={<CheckBoxIcon fontSize="small" />}
|
||||||
|
style={{ marginRight: 8 }}
|
||||||
|
checked={selected}
|
||||||
|
/>}
|
||||||
|
<div title={option} className={styles.title}>{option}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
renderTags={() => <div className={styles.optionListItem}>
|
||||||
|
<div title={selectedValues?.length > 0 ? `${selectedValues[0]} (+${selectedValues.length - 1})` : ""} className={styles.optionListItemTitle}>
|
||||||
|
{selectedValues?.length > 0 ? `${selectedValues[0]}` : ""}
|
||||||
|
</div>
|
||||||
|
{selectedValues?.length > 1 && <div style={{ marginLeft: 5 }}>{`(+${selectedValues.length - 1})`}</div>}
|
||||||
|
</div>}
|
||||||
|
renderInput={(params) => <TextField
|
||||||
|
onChange={(e) => freeSolo && onChange(e.target.value)}
|
||||||
|
variant="outlined" label={label}
|
||||||
|
className={`${classes.root} searchableDropdown`}
|
||||||
|
style={{ backgroundColor: "transparent" }}
|
||||||
|
{...params}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchableDropdown;
|
||||||
@@ -13,7 +13,7 @@ module.exports = {
|
|||||||
instanceOfMiniCssExtractPlugin.options.ignoreOrder = true;
|
instanceOfMiniCssExtractPlugin.options.ignoreOrder = true;
|
||||||
|
|
||||||
webpackConfig.resolve.alias['react']= path.resolve(__dirname, 'node_modules/react'); // solve 2 react instances
|
webpackConfig.resolve.alias['react']= path.resolve(__dirname, 'node_modules/react'); // solve 2 react instances
|
||||||
|
webpackConfig.resolve.alias['@material-ui/styles']= path.resolve("node_modules", "@material-ui/styles");
|
||||||
|
|
||||||
return webpackConfig;
|
return webpackConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,11 +51,13 @@
|
|||||||
"react-error-overlay": "6.0.9"
|
"react-error-overlay": "6.0.9"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"prestart": "../devops/ui-common-pack.sh $PWD",
|
||||||
"start": "craco start",
|
"start": "craco start",
|
||||||
"start-dev": "./node_modules/.bin/env-cmd -f .env.dev.basic craco start",
|
"start-dev": "./node_modules/.bin/env-cmd -f .env.dev.basic craco start",
|
||||||
"build": "./node_modules/.bin/env-cmd -f .env.basic craco build",
|
"build": "./node_modules/.bin/env-cmd -f .env.basic craco build",
|
||||||
"test": "craco test",
|
"test": "craco test",
|
||||||
"eject": "craco eject"
|
"eject": "craco eject",
|
||||||
|
"eslint": "eslint . --ext .js,.jsx,.ts,.tsx --max-warnings=0"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
|||||||
Reference in New Issue
Block a user