├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── CONTRIBUTING.md
├── DESIGN.md
├── Dockerfile
├── LICENSE
├── README.md
├── VERSION
├── cmd
├── fleetspeak_admin
│ └── fleetspeak_admin.go
├── fleetspeak_client
│ └── fleetspeak_client.go
├── fleetspeak_config
│ └── fleetspeak_config.go
└── fleetspeak_server
│ └── fleetspeak_server.go
├── docs
├── DB-PRUNING.md
└── guide.md
├── fleetspeak
├── build-pkgs.sh
├── build.sh
├── client-mac
│ ├── Distribution.xml
│ ├── build.sh
│ ├── com.google.code.fleetspeak.plist
│ ├── communicator.txt
│ └── postinstall
├── client-pkg-tmpl
│ ├── debian
│ │ ├── compat
│ │ ├── control
│ │ ├── docs
│ │ ├── fleetspeak-client.service
│ │ ├── install
│ │ ├── postinst
│ │ └── rules
│ ├── etc
│ │ └── fleetspeak-client
│ │ │ └── communicator.txt
│ └── usr
│ │ └── share
│ │ └── doc
│ │ └── fleetspeak-client
│ │ └── copyright
├── client-wheel
│ └── setup.py
├── client-win
│ ├── build.ps1
│ ├── fleetspeak.wxs
│ └── fleetspeak_lib.wxs
├── generate_protos.sh
├── generate_protos_setup.sh
├── server-pkg-tmpl
│ ├── debian
│ │ ├── compat
│ │ ├── conffiles
│ │ ├── control
│ │ ├── docs
│ │ ├── fleetspeak-server.service
│ │ ├── install
│ │ ├── postinst
│ │ └── rules
│ ├── etc
│ │ └── fleetspeak-server
│ │ │ ├── configurator.config
│ │ │ └── server.services.config
│ └── usr
│ │ └── share
│ │ └── doc
│ │ └── fleetspeak-server
│ │ └── copyright
├── server-wheel
│ └── setup.py
├── src
│ ├── admin
│ │ ├── cli
│ │ │ └── cli.go
│ │ └── history
│ │ │ ├── history.go
│ │ │ └── history_test.go
│ ├── client
│ │ ├── channel
│ │ │ ├── channel.go
│ │ │ ├── channel_test.go
│ │ │ ├── proto
│ │ │ │ └── fleetspeak_channel
│ │ │ │ │ ├── channel.pb.go
│ │ │ │ │ └── channel.proto
│ │ │ ├── relentless.go
│ │ │ └── relentless_test.go
│ │ ├── client.go
│ │ ├── client_test.go
│ │ ├── clienttestutils
│ │ │ └── clienttestutils.go
│ │ ├── clitesting
│ │ │ └── fake_service_context.go
│ │ ├── comms.go
│ │ ├── comms
│ │ │ └── comms.go
│ │ ├── comms_test.go
│ │ ├── config
│ │ │ ├── config.go
│ │ │ ├── filesystem_persistence_handler.go
│ │ │ ├── noop_persistence_handler.go
│ │ │ └── windows_registry_persistence_handler.go
│ │ ├── daemonservice
│ │ │ ├── client
│ │ │ │ └── direct.go
│ │ │ ├── command
│ │ │ │ ├── command.go
│ │ │ │ ├── command_unix.go
│ │ │ │ └── command_windows.go
│ │ │ ├── daemonservice.go
│ │ │ ├── daemonservice_oss_test.go
│ │ │ ├── daemonservice_test.go
│ │ │ ├── execution
│ │ │ │ ├── execution.go
│ │ │ │ ├── execution_oss_test.go
│ │ │ │ └── execution_test.go
│ │ │ ├── proto
│ │ │ │ └── fleetspeak_daemonservice
│ │ │ │ │ ├── config.pb.go
│ │ │ │ │ ├── config.proto
│ │ │ │ │ ├── messages.pb.go
│ │ │ │ │ └── messages.proto
│ │ │ └── testclient
│ │ │ │ └── testclient.go
│ │ ├── entry
│ │ │ ├── entry.go
│ │ │ ├── entry_unix.go
│ │ │ └── entry_windows.go
│ │ ├── flow
│ │ │ ├── filter.go
│ │ │ └── filter_test.go
│ │ ├── generic
│ │ │ ├── config.go
│ │ │ ├── config_unix.go
│ │ │ ├── config_windows.go
│ │ │ └── proto
│ │ │ │ └── fleetspeak_client_generic
│ │ │ │ ├── config.pb.go
│ │ │ │ └── config.proto
│ │ ├── https
│ │ │ ├── compression.go
│ │ │ ├── https.go
│ │ │ ├── https_test.go
│ │ │ ├── polling.go
│ │ │ ├── polling_test.go
│ │ │ ├── streaming.go
│ │ │ └── streaming_test.go
│ │ ├── internal
│ │ │ ├── config
│ │ │ │ ├── manager.go
│ │ │ │ └── manager_test.go
│ │ │ ├── message
│ │ │ │ ├── retry.go
│ │ │ │ ├── retry_test.go
│ │ │ │ ├── sort.go
│ │ │ │ └── sort_test.go
│ │ │ ├── monitoring
│ │ │ │ ├── resource_usage_fetcher.go
│ │ │ │ ├── resource_usage_fetcher_test.go
│ │ │ │ ├── resource_usage_fetcher_unix.go
│ │ │ │ ├── resource_usage_monitor.go
│ │ │ │ └── resource_usage_monitor_test.go
│ │ │ └── process
│ │ │ │ └── process.go
│ │ ├── proto
│ │ │ └── fleetspeak_client
│ │ │ │ ├── api.pb.go
│ │ │ │ ├── api.proto
│ │ │ │ ├── client.pb.go
│ │ │ │ └── client.proto
│ │ ├── service
│ │ │ └── service.go
│ │ ├── services.go
│ │ ├── signer
│ │ │ └── signer.go
│ │ ├── socketservice
│ │ │ ├── checks
│ │ │ │ ├── sock_checks_unix.go
│ │ │ │ └── sock_checks_windows.go
│ │ │ ├── client
│ │ │ │ ├── proxy.go
│ │ │ │ ├── proxy_unix.go
│ │ │ │ └── proxy_windows.go
│ │ │ ├── proto
│ │ │ │ └── fleetspeak_socketservice
│ │ │ │ │ ├── config.pb.go
│ │ │ │ │ └── config.proto
│ │ │ ├── socketservice.go
│ │ │ ├── socketservice_oss_test.go
│ │ │ ├── socketservice_test.go
│ │ │ ├── socketservice_unix.go
│ │ │ ├── socketservice_windows.go
│ │ │ └── testclient
│ │ │ │ └── testclient.go
│ │ ├── stats
│ │ │ └── collector.go
│ │ ├── stdinservice
│ │ │ ├── proto
│ │ │ │ └── fleetspeak_stdinservice
│ │ │ │ │ ├── config.pb.go
│ │ │ │ │ ├── config.proto
│ │ │ │ │ ├── messages.pb.go
│ │ │ │ │ └── messages.proto
│ │ │ ├── stdinservice.go
│ │ │ └── stdinservice_test.go
│ │ ├── system_service.go
│ │ ├── system_service_test.go
│ │ └── watchdog
│ │ │ ├── watchdog.go
│ │ │ ├── watchdog_test.go
│ │ │ ├── watchdog_unix.go
│ │ │ └── watchdog_windows.go
│ ├── common
│ │ ├── anypbtest
│ │ │ └── anypbtest.go
│ │ ├── fscontext
│ │ │ ├── fscontext.go
│ │ │ └── fscontext_test.go
│ │ ├── ids.go
│ │ ├── ids_test.go
│ │ ├── proto
│ │ │ ├── fleetspeak
│ │ │ │ ├── common.pb.go
│ │ │ │ ├── common.proto
│ │ │ │ ├── system.pb.go
│ │ │ │ └── system.proto
│ │ │ └── fleetspeak_monitoring
│ │ │ │ ├── resource.pb.go
│ │ │ │ └── resource.proto
│ │ └── should
│ │ │ └── never_oss.go
│ ├── comtesting
│ │ ├── server_cert.go
│ │ ├── tempdir.go
│ │ ├── tempdir_unix.go
│ │ └── tempdir_windows.go
│ ├── config
│ │ ├── certs
│ │ │ ├── server.go
│ │ │ └── trusted.go
│ │ ├── client
│ │ │ └── config.go
│ │ ├── proto
│ │ │ └── fleetspeak_config
│ │ │ │ ├── config.pb.go
│ │ │ │ └── config.proto
│ │ └── server
│ │ │ └── config.go
│ ├── e2etesting
│ │ ├── README.md
│ │ ├── balancer
│ │ │ ├── balancer.go
│ │ │ └── proxyproto
│ │ │ │ └── proxyproto.go
│ │ ├── frr_master_server_main
│ │ │ └── frr_master_server_main.go
│ │ ├── localtesting
│ │ │ └── end_to_end_test.go
│ │ ├── setup
│ │ │ └── setup_components.go
│ │ └── tests
│ │ │ └── end_to_end_tests.go
│ ├── inttesting
│ │ ├── frr
│ │ │ ├── frr.go
│ │ │ ├── frr_test.go
│ │ │ └── proto
│ │ │ │ └── fleetspeak_frr
│ │ │ │ ├── frr.pb.go
│ │ │ │ ├── frr.proto
│ │ │ │ └── frr_grpc.pb.go
│ │ ├── integration_test.go
│ │ └── integrationtest
│ │ │ ├── clone.go
│ │ │ ├── frr.go
│ │ │ └── sigs.go
│ ├── server
│ │ ├── admin
│ │ │ └── admin.go
│ │ ├── authorizer
│ │ │ └── authorizer.go
│ │ ├── comms.go
│ │ ├── comms
│ │ │ └── comms.go
│ │ ├── components
│ │ │ ├── authorizer
│ │ │ │ └── authorizer.go
│ │ │ ├── components.go
│ │ │ ├── components_test.go
│ │ │ ├── https
│ │ │ │ └── proxy.go
│ │ │ ├── notifications
│ │ │ │ ├── http.go
│ │ │ │ └── http_test.go
│ │ │ ├── prometheus
│ │ │ │ └── prometheus.go
│ │ │ └── proto
│ │ │ │ └── fleetspeak_components
│ │ │ │ ├── config.pb.go
│ │ │ │ └── config.proto
│ │ ├── cpsservice
│ │ │ ├── proto
│ │ │ │ └── fleetspeak_cpsservice
│ │ │ │ │ ├── cpsservice.pb.go
│ │ │ │ │ └── cpsservice.proto
│ │ │ ├── service.go
│ │ │ └── service_test.go
│ │ ├── db
│ │ │ ├── store.go
│ │ │ └── time.go
│ │ ├── dbtesting
│ │ │ ├── broadcaststore_suite.go
│ │ │ ├── clientstore_suite.go
│ │ │ ├── dbtesting.go
│ │ │ ├── filestore_suite.go
│ │ │ ├── integration_suite.go
│ │ │ └── messagestore_suite.go
│ │ ├── grpcservice
│ │ │ ├── client
│ │ │ │ └── testing
│ │ │ │ │ ├── client_test.sh
│ │ │ │ │ └── tester.go
│ │ │ ├── proto
│ │ │ │ └── fleetspeak_grpcservice
│ │ │ │ │ ├── grpcservice.pb.go
│ │ │ │ │ ├── grpcservice.proto
│ │ │ │ │ └── grpcservice_grpc.pb.go
│ │ │ ├── service.go
│ │ │ └── service_test.go
│ │ ├── https
│ │ │ ├── client_certificate.go
│ │ │ ├── client_certificate_test.go
│ │ │ ├── compression.go
│ │ │ ├── file_server.go
│ │ │ ├── https.go
│ │ │ ├── https_test.go
│ │ │ ├── message_server.go
│ │ │ └── streaming_message_server.go
│ │ ├── ids
│ │ │ └── ids.go
│ │ ├── internal
│ │ │ ├── broadcasts
│ │ │ │ ├── broadcasts.go
│ │ │ │ └── broadcasts_test.go
│ │ │ ├── cache
│ │ │ │ ├── cache.go
│ │ │ │ └── cache_test.go
│ │ │ ├── ftime
│ │ │ │ ├── ftime.go
│ │ │ │ └── retry.go
│ │ │ ├── notifications
│ │ │ │ ├── notifications.go
│ │ │ │ └── notifications_test.go
│ │ │ ├── services
│ │ │ │ ├── manager.go
│ │ │ │ └── system_service.go
│ │ │ └── signatures
│ │ │ │ └── validation.go
│ │ ├── mysql
│ │ │ ├── broadcaststore.go
│ │ │ ├── clientstore.go
│ │ │ ├── filestore.go
│ │ │ ├── messagestore.go
│ │ │ ├── mysql.go
│ │ │ └── mysql_test.go
│ │ ├── notifications
│ │ │ └── notifications.go
│ │ ├── proto
│ │ │ └── fleetspeak_server
│ │ │ │ ├── admin.pb.go
│ │ │ │ ├── admin.proto
│ │ │ │ ├── admin_grpc.pb.go
│ │ │ │ ├── broadcasts.pb.go
│ │ │ │ ├── broadcasts.proto
│ │ │ │ ├── resource.pb.go
│ │ │ │ ├── resource.proto
│ │ │ │ ├── server.pb.go
│ │ │ │ ├── server.proto
│ │ │ │ ├── services.pb.go
│ │ │ │ └── services.proto
│ │ ├── sertesting
│ │ │ ├── cache.go
│ │ │ ├── context.go
│ │ │ ├── retry.go
│ │ │ └── time.go
│ │ ├── server.go
│ │ ├── servertests
│ │ │ ├── admin_test.go
│ │ │ ├── comms_test.go
│ │ │ └── system_service_test.go
│ │ ├── service
│ │ │ ├── service.go
│ │ │ └── service_test.go
│ │ ├── spanner
│ │ │ ├── broadcaststore.go
│ │ │ ├── clientstore.go
│ │ │ ├── filestore.go
│ │ │ ├── messagestore.go
│ │ │ ├── spanner.go
│ │ │ └── spanner_test.go
│ │ ├── sqlite
│ │ │ ├── broadcaststore.go
│ │ │ ├── clientstore.go
│ │ │ ├── filestore.go
│ │ │ ├── messagestore.go
│ │ │ ├── sqlite.go
│ │ │ └── sqlite_test.go
│ │ ├── stats.go
│ │ ├── stats
│ │ │ └── collector.go
│ │ └── testserver
│ │ │ └── testserver.go
│ └── windows
│ │ ├── hashpipe
│ │ ├── hashpipe.go
│ │ ├── hashpipe_test.go
│ │ ├── hashpipe_windows.go
│ │ └── hashpipe_windows_test.go
│ │ ├── regutil
│ │ ├── regutil.go
│ │ ├── regutil_test.go
│ │ ├── regutil_windows.go
│ │ └── regutil_windows_test.go
│ │ └── wnixsocket
│ │ ├── wnixsocket.go
│ │ ├── wnixsocket_test.go
│ │ ├── wnixsocket_windows.go
│ │ └── wnixsocket_windows_test.go
├── test-package.sh
└── test.sh
├── fleetspeak_python
├── fleetspeak
│ ├── client_connector
│ │ ├── connector.py
│ │ └── testing
│ │ │ ├── testclient.py
│ │ │ └── testclient_launcher.py
│ └── server_connector
│ │ ├── connector.py
│ │ ├── connector_test.py
│ │ └── testing
│ │ └── loopback.py
└── setup.py
├── frr_python
├── frr_client.py
├── frr_server.py
└── setup.py
├── go.mod
├── go.sum
├── sandboxes
├── README.md
├── cleartext-header-mode
│ ├── README.md
│ ├── config
│ │ ├── fleetspeak-client
│ │ │ ├── communicator.txt
│ │ │ ├── config.textproto
│ │ │ └── textservices
│ │ │ │ └── hello.service
│ │ ├── fleetspeak-server
│ │ │ ├── components.textproto
│ │ │ └── services.textproto
│ │ ├── fleetspeak.textproto
│ │ ├── hello.py
│ │ └── hello.sh
│ ├── docker-compose.yaml
│ └── envoy-https-http.yaml
├── cleartext-xfcc-mode
│ ├── README.md
│ ├── config
│ │ ├── fleetspeak-client
│ │ │ ├── communicator.txt
│ │ │ ├── config.textproto
│ │ │ └── textservices
│ │ │ │ └── hello.service
│ │ ├── fleetspeak-server
│ │ │ ├── components.textproto
│ │ │ └── services.textproto
│ │ ├── fleetspeak.textproto
│ │ ├── hello.py
│ │ └── hello.sh
│ ├── docker-compose.yaml
│ └── envoy-https-http.yaml
├── createConfig.sh
├── diagrams
│ ├── cleartextHeaderMode_355.png
│ ├── cleartextXfccMode_355.png
│ ├── directMode_355.png
│ ├── httpsHeaderMode_355.png
│ └── passthroughMode_355.png
├── direct-mtls-mode
│ ├── README.md
│ ├── config
│ │ ├── fleetspeak-client
│ │ │ ├── communicator.txt
│ │ │ ├── config.textproto
│ │ │ └── textservices
│ │ │ │ └── hello.service
│ │ ├── fleetspeak-server
│ │ │ ├── components.textproto
│ │ │ └── services.textproto
│ │ ├── fleetspeak.textproto
│ │ ├── hello.py
│ │ └── hello.sh
│ └── docker-compose.yaml
├── https-header-mode
│ ├── README.md
│ ├── config
│ │ ├── fleetspeak-client
│ │ │ ├── communicator.txt
│ │ │ ├── config.textproto
│ │ │ └── textservices
│ │ │ │ └── hello.service
│ │ ├── fleetspeak-server
│ │ │ ├── components.textproto
│ │ │ └── services.textproto
│ │ ├── fleetspeak.textproto
│ │ ├── hello.py
│ │ └── hello.sh
│ ├── docker-compose.yaml
│ └── envoy-https-https.yaml
├── passthrough-mode
│ ├── README.md
│ ├── config
│ │ ├── fleetspeak-client
│ │ │ ├── communicator.txt
│ │ │ ├── config.textproto
│ │ │ └── textservices
│ │ │ │ └── hello.service
│ │ ├── fleetspeak-server
│ │ │ ├── components.textproto
│ │ │ └── services.textproto
│ │ ├── fleetspeak.textproto
│ │ ├── hello.py
│ │ └── hello.sh
│ ├── docker-compose.yaml
│ └── envoy-https-passthrough.yaml
└── shared
│ ├── envoy
│ └── Dockerfile
│ ├── fleetspeak-client
│ └── Dockerfile
│ ├── fleetspeak-server
│ └── Dockerfile
│ └── greeter
│ ├── Dockerfile
│ └── greeter.py
├── spanner-setup
├── Dockerfile.dev
├── SPANNER.md
├── docker-compose.yaml
├── fleetspeak.pb
└── setup.sh
└── terraform
├── README.md
├── cloudtesting
└── end_to_end_test.go
├── fleetspeak_configurator
└── build_configs.go
├── fs_client_start.sh
├── fs_server_start.sh
├── main.tf
├── main_vm_start.sh
└── master_server_start.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | # Common temporary and build artifact file types.
2 | *.pyc
3 | *.swp
4 | *.o
5 | *.so
6 | *.pb.cc
7 | *.pb.h
8 | *~
9 | .idea
10 | *.deb
11 |
12 | # Autogenerated Python files (unlike go proto-files,
13 | # these do not need to be checked in).
14 | *_pb2.py
15 | *_pb2_grpc.py
16 |
17 | # Generated when installing the Python lib.
18 | fleetspeak.egg-info/
19 |
20 | # Binaries created by fleetspeak/build.sh
21 | cmd/*/*
22 | !cmd/*/*.go
23 |
24 | fleetspeak/src/client/client/client
25 | fleetspeak/src/client/client/client.exe
26 | fleetspeak/src/client/daemonservice/testclient/testclient
27 | fleetspeak/src/client/daemonservice/testclient/testclient.exe
28 | fleetspeak/src/client/socketservice/testclient/testclient
29 | fleetspeak/src/client/socketservice/testclient/testclient.exe
30 | fleetspeak/src/server/grpcservice/client/testing/tester
31 |
32 | # Directory laying out debian package structures, fully populated by
33 | # fleetspeak/build-pkgs.sh
34 | fleetspeak/server-pkg/
35 | fleetspeak/client-pkg/
36 |
37 | fleetspeak/src/e2etesting/balancer/balancer
38 | fleetspeak/src/e2etesting/frr-master-server-main/frr_master_server_main
39 |
40 | # Ignore pki files
41 | *.pem
42 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution,
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.22 AS builder
2 |
3 | RUN apt-get update && \
4 | apt-get install -y \
5 | python-is-python3
6 |
7 | COPY . /fleetspeak
8 |
9 | ENV GOBIN=/fleetspeak/bin
10 | RUN mkdir -p $GOBIN
11 | RUN cd /fleetspeak && go install ./...
12 |
13 |
14 | FROM golang:1.22
15 |
16 | RUN apt update
17 |
18 | WORKDIR /
19 |
20 | ENV FLEETSPEAK_BIN=/fleetspeak/bin
21 | RUN mkdir -p $FLEETSPEAK_BIN
22 |
23 | COPY --from=builder /fleetspeak/bin/fleetspeak_server $FLEETSPEAK_BIN/server
24 | COPY --from=builder /fleetspeak/bin/fleetspeak_client $FLEETSPEAK_BIN/client
25 | COPY --from=builder /fleetspeak/bin/fleetspeak_config $FLEETSPEAK_BIN
26 | COPY --from=builder /fleetspeak/bin/fleetspeak_admin $FLEETSPEAK_BIN
27 |
28 | ENV PATH="$FLEETSPEAK_BIN:$PATH"
29 |
30 | ENTRYPOINT [ "server" ]
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fleetspeak
2 |
3 | [](https://github.com/google/fleetspeak/actions/workflows/build.yml)
4 | [](https://goreportcard.com/report/github.com/google/fleetspeak)
5 |
6 | Fleetspeak is a framework for communicating with a fleet of machines, with a
7 | focus on security monitoring and basic administrative use cases. It is a
8 | subproject of [GRR](https://github.com/google/grr/blob/master/README.md), and
9 | can be seen as an effort to modularizing and modernizing its communication
10 | mechanism.
11 |
12 | ## Status
13 |
14 | We have this code working internally as part of our GRR installation.
15 |
16 | ## Getting Started
17 |
18 | On linux, assuming a recent version of the go development environment (see the
19 | `go.mod` file for the exact requirement) and virtualenv, the following sequence
20 | of commands will build and test this pre-release:
21 |
22 | ```bash
23 | go get -v -t github.com/google/fleetspeak/...
24 |
25 | # Assuming default $GOPATH:
26 | cd ~/go/src/github.com/google/fleetspeak
27 |
28 | # Setup virtualenv - fleetspeak provides some python integration libraries,
29 | # and this ensures they are set up in a known way.
30 | virtualenv $HOME/FSENV
31 | source $HOME/FSENV/bin/activate
32 |
33 | pip install -e fleetspeak_python/
34 |
35 | # Set mysql parameters. The mysql datastore test will run if the following environment
36 | # variables are set. Otherwise it will be skipped.
37 | export MYSQL_TEST_USER=
38 | export MYSQL_TEST_PASS= # will assume null password if unset.
39 | export MYSQL_TEST_ADDR=
40 |
41 | # Build and test the release:
42 | fleetspeak/build.sh
43 | fleetspeak/test.sh
44 |
45 | # After modifying proto files, the resulting go and python files need to be regenerated:
46 | go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1
47 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.4
48 | fleetspeak/generate_go_py_protos.sh
49 | ```
50 |
51 | Once built, you can take a look at the files and instructions in our
52 | [demo directory](https://github.com/google/fleetspeak/tree/master/fleetspeak/src/demo).
53 |
54 | ## DISCLAIMER
55 |
56 | While the code presented here is in some sense feature complete, much of it is
57 | barely tested or documented, and breaking changes are still possible. Therefore,
58 | please consider this a preview release while the dust settles. Suggestions and
59 | pull requests are very much appreciated.
60 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.1.18
2 |
--------------------------------------------------------------------------------
/cmd/fleetspeak_admin/fleetspeak_admin.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package main implements a general command line interface which performs
16 | // administrative actions on a fleetspeak installation.
17 | //
18 | // Most functionality is implemented by the cli sub-package. Installations may
19 | // want to branch this file to adjust the default admin_addr flag, dial
20 | // parameters and similar.
21 | package main
22 |
23 | import (
24 | "flag"
25 |
26 | log "github.com/golang/glog"
27 | "google.golang.org/grpc"
28 | "google.golang.org/grpc/credentials/insecure"
29 |
30 | "github.com/google/fleetspeak/fleetspeak/src/admin/cli"
31 | )
32 |
33 | var adminAddr = flag.String("admin_addr", "localhost:6061", "Address for the admin server.")
34 |
35 | func main() {
36 | flag.Parse()
37 |
38 | conn, err := grpc.Dial(*adminAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
39 | if err != nil {
40 | log.Exitf("Unable to connect to fleetspeak admin interface [%v]: %v", *adminAddr, err)
41 | }
42 |
43 | cli.Execute(conn, flag.Args()...)
44 | }
45 |
--------------------------------------------------------------------------------
/fleetspeak/build-pkgs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright 2019 Google LLC.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | set -e
17 |
18 | /bin/echo >&2 ""
19 | /bin/echo >&2 "Building binaries"
20 |
21 | export BINDIR="$(mktemp -d)"
22 | trap "rm -rf ${BINDIR}" EXIT
23 |
24 | cd ..
25 | CGO_ENABLED=0 GOBIN="${BINDIR}" go install ./cmd/...
26 | cd -
27 |
28 | /bin/echo >&2 ""
29 | /bin/echo >&2 "Building server.deb"
30 |
31 | export DEB_DEST="server-pkg/debian/fleetspeak-server"
32 | export DEB_VERSION=$(cat ../VERSION)
33 |
34 | fakeroot bash -c '
35 | set -e
36 | rm -rf server-pkg
37 | cp -r server-pkg-tmpl server-pkg
38 |
39 | chmod 755 server-pkg/*
40 |
41 | cd server-pkg
42 | debchange --create \
43 | --newversion "${DEB_VERSION}" \
44 | --package fleetspeak-server \
45 | --urgency low \
46 | --controlmaint \
47 | --distribution unstable \
48 | "Built by GitHub Actions at ${GITHUB_SHA}"
49 | cd -
50 |
51 | mkdir -p server-pkg/usr/bin
52 | install -o root -g root "${BINDIR}/fleetspeak_server" server-pkg/usr/bin/fleetspeak-server
53 | install -o root -g root "${BINDIR}/fleetspeak_config" server-pkg/usr/bin/fleetspeak-config
54 | install -o root -g root "${BINDIR}/fleetspeak_admin" server-pkg/usr/bin/fleetspeak-admin
55 |
56 | cd server-pkg
57 | dpkg-buildpackage -us -uc
58 | cd -
59 | '
60 |
61 | /bin/echo >&2 ""
62 | /bin/echo >&2 "Building client.deb"
63 | fakeroot bash -c '
64 | set -e
65 | rm -rf client-pkg
66 | cp -r client-pkg-tmpl client-pkg
67 |
68 | chmod 755 client-pkg/*
69 |
70 | cd client-pkg
71 | debchange --create \
72 | --newversion "${DEB_VERSION}" \
73 | --package fleetspeak-client \
74 | --urgency low \
75 | --controlmaint \
76 | --distribution unstable \
77 | "Built by GitHub Actions at ${GITHUB_SHA}"
78 | cd -
79 |
80 | mkdir -p client-pkg/usr/bin
81 | install -o root -g root "${BINDIR}/fleetspeak_client" client-pkg/usr/bin/fleetspeak-client
82 |
83 | cd client-pkg
84 | dpkg-buildpackage -us -uc
85 | cd -
86 | '
87 |
--------------------------------------------------------------------------------
/fleetspeak/client-mac/Distribution.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Fleetspeak Client
4 | com.google.code
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | fleetspeak-client-component.xar
17 |
18 |
19 |
--------------------------------------------------------------------------------
/fleetspeak/client-mac/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -ex
4 |
5 | realpath() {
6 | [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
7 | }
8 |
9 | CONFIGS_DIR=$(pwd)
10 | FS_BINARY=$(realpath $1)
11 | FS_VERSION=$(cat ../../VERSION)
12 | COMPONENT_PKG_NAME="fleetspeak-client-component.xar"
13 | PRODUCT_ARCHIVE_NAME="fleetspeak-client-${FS_VERSION}.pkg"
14 |
15 | rm -rf ./work
16 | mkdir work
17 | cd work
18 |
19 | mkdir -p pkg_root/Library/LaunchDaemons
20 | mkdir -p pkg_root/etc/fleetspeak-client/services
21 | mkdir -p pkg_root/etc/fleetspeak-client/textservices
22 |
23 | # We install the Fleetspeak binary in /usr/local/bin, and
24 | # not /usr/sbin (as we do for Linux), because MacOS won't let us:
25 | # https://en.wikipedia.org/wiki/System_Integrity_Protection.
26 | mkdir -p pkg_root/usr/local/bin
27 |
28 | # Copy postinstall script.
29 | mkdir install-scripts
30 | cp "${CONFIGS_DIR}/postinstall" install-scripts
31 | chmod +x install-scripts/*
32 |
33 | cp "${CONFIGS_DIR}/com.google.code.fleetspeak.plist" pkg_root/Library/LaunchDaemons
34 | cp "${CONFIGS_DIR}/communicator.txt" pkg_root/etc/fleetspeak-client/
35 | cp "${FS_BINARY}" pkg_root/usr/local/bin/fleetspeak-client
36 |
37 | # Set permissions for files and directories in the payload.
38 | find pkg_root -type d -exec chmod 755 {} \;
39 | find pkg_root -type f -exec chmod 644 {} \;
40 | chmod +x pkg_root/usr/local/bin/fleetspeak-client
41 |
42 | # Create a component package containing files to be installed.
43 | pkgbuild \
44 | --root pkg_root \
45 | --identifier com.google.code.fleetspeak \
46 | --version "${FS_VERSION}" \
47 | --scripts install-scripts \
48 | "${COMPONENT_PKG_NAME}"
49 |
50 | # Copy over distribution file.
51 | cp "${CONFIGS_DIR}/Distribution.xml" ./
52 | # Interpolate the version in the distribution file.
53 | # The tilde after the 'i' flag is the suffix to use for the backup file
54 | # created by sed.
55 | sed -i~ "s:\$VERSION:${FS_VERSION}:g" Distribution.xml
56 | rm -f 'Distribution.xml~'
57 |
58 | # Create final product archive.
59 | productbuild --distribution Distribution.xml --package-path "${COMPONENT_PKG_NAME}" "${PRODUCT_ARCHIVE_NAME}"
60 |
61 |
--------------------------------------------------------------------------------
/fleetspeak/client-mac/com.google.code.fleetspeak.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Label
6 | com.google.code.fleetspeak
7 | UserName
8 | root
9 | GroupName
10 | daemon
11 | ProgramArguments
12 |
13 | /usr/local/bin/fleetspeak-client
14 | --config=/etc/fleetspeak-client/client.config
15 | --log_dir=/private/var/log
16 |
17 | KeepAlive
18 |
19 | RunAtLoad
20 |
21 | ThrottleInterval
22 | 120
23 | ServiceDescription
24 | Fleetspeak Client
25 | StandardOutPath
26 | /dev/null
27 | StandardErrorPath
28 | /dev/null
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/fleetspeak/client-mac/communicator.txt:
--------------------------------------------------------------------------------
1 | # This is a text format fleetspeak_client.CommunicatorConfig and can be used
2 | # to tweak how often fleetspeak tries to ping the server.
3 | #
4 | # Example values for debugging:
5 | #
6 | # max_poll_delay_seconds: 10
7 | # max_buffer_delay_seconds: 1
8 | # min_failure_delay_seconds: 10
9 |
10 |
--------------------------------------------------------------------------------
/fleetspeak/client-mac/postinstall:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | # Abort if package install is not happening on the running volume.
6 | [[ $3 != '/' ]] && exit 0
7 |
8 | readonly DAEMON_PLIST=/Library/LaunchDaemons/com.google.code.fleetspeak.plist
9 |
10 | # Restart the Fleetspeak process.
11 | if [[ -f "${DAEMON_PLIST}" ]]; then
12 | launchctl unload "${DAEMON_PLIST}" || true
13 | launchctl load -w "${DAEMON_PLIST}"
14 | fi
15 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/debian/compat:
--------------------------------------------------------------------------------
1 | 9
2 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/debian/control:
--------------------------------------------------------------------------------
1 | Source: fleetspeak-client
2 | Maintainer: GRR Dev
3 | Build-Depends: debhelper (>= 9), debhelper (>= 9.20160709), devscripts
4 | Standards-Version: 3.8.3
5 | Homepage: https://github.com/google/fleetspeak
6 |
7 | Package: fleetspeak-client
8 | Architecture: any
9 | Pre-Depends:
10 | Depends: systemd
11 | Description: client for the Fleetspeak communications framework
12 | Fleetspeak is a framework for communicating with a fleet of machines, with a
13 | focus on security and administrative tasks.
14 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/debian/docs:
--------------------------------------------------------------------------------
1 | usr/share/doc/fleetspeak-client/*
2 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/debian/fleetspeak-client.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Fleetspeak Client Service
3 | After=syslog.target network.target
4 | Documentation=https://github.com/google/fleetspeak
5 |
6 | [Service]
7 | User=root
8 | ExecStart=/usr/bin/fleetspeak-client --config /etc/fleetspeak-client/client.config
9 | ExecReload=kill -s HUP $MAINPID
10 | Restart=always
11 | KillMode=process
12 |
13 | [Install]
14 | WantedBy=multi-user.target
15 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/debian/install:
--------------------------------------------------------------------------------
1 | etc/fleetspeak-client/communicator.txt etc/fleetspeak-client
2 | usr/bin/fleetspeak-client usr/bin
3 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/debian/postinst:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Post-installation script for the Fleetspeak client deb.
4 | #
5 |
6 | set -e
7 |
8 | # The token below is replaced with shellscript snippets generated
9 | # by debhelper commands. See http://manpages.ubuntu.com/dh_installdeb
10 |
11 | #DEBHELPER#
12 |
13 | case "$1" in
14 | configure)
15 | ;;
16 | esac
17 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | # -*- makefile -*-
3 |
4 | # Uncomment this to turn on verbose mode.
5 | # export DH_VERBOSE=1
6 |
7 | %:
8 | dh $@ --with systemd
9 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/etc/fleetspeak-client/communicator.txt:
--------------------------------------------------------------------------------
1 | # This is a text format fleetspeak.client.CommunicatorConfig and can be used
2 | # to tweak how often the fleetspeak client tries to ping the server.
3 | #
4 | # Example values for debugging:
5 | #
6 | # max_poll_delay_seconds: 10
7 | # max_buffer_delay_seconds: 1
8 | # min_failure_delay_seconds: 10
9 |
10 |
--------------------------------------------------------------------------------
/fleetspeak/client-pkg-tmpl/usr/share/doc/fleetspeak-client/copyright:
--------------------------------------------------------------------------------
1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: Fleetspeak
3 | Upstream-Contact: GRR Dev
4 | Source: https://github.com/google/fleetspeak
5 |
6 | Files: *
7 | Copyright: 2017-2018 Google
8 | License: Apache-2.0
9 |
--------------------------------------------------------------------------------
/fleetspeak/client-wheel/setup.py:
--------------------------------------------------------------------------------
1 | from optparse import OptionParser
2 | import pathlib
3 | import sys
4 |
5 | from setuptools import setup
6 | from wheel.bdist_wheel import bdist_wheel
7 |
8 |
9 | class BdistWheel(bdist_wheel):
10 | user_options = [
11 | ("platform-name=", None, "Platform name to force."),
12 | ]
13 |
14 | def initialize_options(self):
15 | self.platform_name = None
16 | bdist_wheel.initialize_options(self)
17 |
18 | def finalize_options(self):
19 | bdist_wheel.finalize_options(self)
20 | self.root_is_pure = False
21 |
22 | def get_tag(self):
23 | impl, abi_tag, plat_name = bdist_wheel.get_tag(self)
24 | if self.platform_name is not None:
25 | plat_name = self.platform_name
26 | return "py2.py3", "none", plat_name
27 |
28 |
29 | def GetOptions():
30 | parser = OptionParser()
31 | parser.add_option("--package-root")
32 | parser.add_option("--version")
33 | options, sys.argv[1:] = parser.parse_args()
34 | for option in "package_root", "version":
35 | if not getattr(options, option):
36 | parser.error("--{} is required.".format(option))
37 | return options
38 |
39 |
40 | def DataFiles(prefix_in_pkg, root_dir):
41 | result = []
42 | for path in pathlib.Path(root_dir).glob("**/*"):
43 | if path.is_dir():
44 | continue
45 | relative = path.relative_to(root_dir)
46 | result.append((str(prefix_in_pkg / relative.parent), [str(path)]))
47 | return result
48 |
49 |
50 | options = GetOptions()
51 |
52 | setup(
53 | name="fleetspeak-client-bin",
54 | version=options.version,
55 | packages=[],
56 | cmdclass={
57 | "bdist_wheel": BdistWheel,
58 | },
59 | data_files=DataFiles("fleetspeak-client-bin", options.package_root),
60 | )
61 |
--------------------------------------------------------------------------------
/fleetspeak/client-win/fleetspeak.wxs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/fleetspeak/generate_protos.sh:
--------------------------------------------------------------------------------
1 | # Exit on error.
2 | set -e
3 |
4 | echo 'Transpiling required protos to Go and Python.'
5 |
6 | # Go to this script's directory.
7 | cd "$(/usr/bin/dirname "$(/bin/readlink -e "${0}")")"
8 |
9 | # Check dependencies.
10 | ./generate_protos_setup.sh check
11 |
12 | find .. -name '*.proto' -print0 | xargs -0 -t -I % protoc \
13 | --go_out=.. --go-grpc_out=.. \
14 | --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative \
15 | --proto_path=.. %
16 |
--------------------------------------------------------------------------------
/fleetspeak/generate_protos_setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | PROTOC_VER="26.1" # https://github.com/protocolbuffers/protobuf/releases
5 | GEN_GO_VER="1.35.1" # https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go?tab=versions
6 | GEN_GO_GRPC_VER="1.5.1" # https://pkg.go.dev/google.golang.org/grpc/cmd/protoc-gen-go-grpc?tab=versions
7 |
8 | function err() {
9 | echo "$*" >&2
10 | }
11 |
12 | # Installs protoc from https://github.com/protocolbuffers/protobuf/releases to
13 | # ~/.local/bin. Well known proto types are placed in ~/.local/include.
14 | # Globals:
15 | # PROTOC_VER
16 | # Arguments:
17 | # None
18 | function install_protoc() {
19 | local temp_zip
20 | temp_zip="$(mktemp)"
21 | trap "rm -f ${temp_zip}" EXIT
22 | curl -L "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VER}/protoc-${PROTOC_VER}-linux-x86_64.zip" -o "${temp_zip}"
23 | unzip -o "${temp_zip}" -x readme.txt -d "${HOME}/.local"
24 | echo "Installed protoc v${PROTOC_VER}. Ensure ${HOME}/.local/bin is in your PATH."
25 | }
26 |
27 | if [[ "$(protoc --version)" != "libprotoc ${PROTOC_VER}" ]]; then
28 | if [[ "$1" == "check" ]]; then
29 | err "Wrong protobuf version, please run fleetspeak/generate_protos_setup.sh"
30 | exit 1
31 | fi
32 | install_protoc
33 | fi
34 |
35 | if [[ "$(protoc-gen-go --version)" != "protoc-gen-go v${GEN_GO_VER}" ]]; then
36 | if [[ "$1" == "check" ]]; then
37 | err "Wrong protoc-gen-go version, please run fleetspeak/generate_protos_setup.sh"
38 | exit 1
39 | fi
40 | go install "google.golang.org/protobuf/cmd/protoc-gen-go@v${GEN_GO_VER}"
41 | fi
42 |
43 | if [[ "$(protoc-gen-go-grpc --version)" != "protoc-gen-go-grpc ${GEN_GO_GRPC_VER}" ]]; then
44 | if [[ "$1" == "check" ]]; then
45 | err "Wrong protoc-gen-go-grpc version, please run fleetspeak/generate_protos_setup.sh"
46 | exit 1
47 | fi
48 | go install "google.golang.org/grpc/cmd/protoc-gen-go-grpc@v${GEN_GO_GRPC_VER}"
49 | fi
50 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/compat:
--------------------------------------------------------------------------------
1 | 9
2 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/conffiles:
--------------------------------------------------------------------------------
1 | /etc/fleetspeak-server/server.services.config
2 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/control:
--------------------------------------------------------------------------------
1 | Source: fleetspeak-server
2 | Maintainer: GRR Dev
3 | Build-Depends: debhelper (>= 9), debhelper (>= 9.20160709), devscripts
4 | Standards-Version: 3.8.3
5 | Homepage: https://github.com/google/fleetspeak
6 |
7 | Package: fleetspeak-server
8 | Architecture: any
9 | Pre-Depends:
10 | Depends: adduser, systemd
11 | Description: server for the Fleetspeak communications framework
12 | Fleetspeak is a framework for communicating with a fleet of machines, with a
13 | focus on security and administrative tasks.
14 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/docs:
--------------------------------------------------------------------------------
1 | usr/share/doc/fleetspeak-server/*
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/fleetspeak-server.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Fleetspeak Server Service
3 | After=syslog.target network.target
4 | After=mysql.service
5 | Documentation=https://github.com/google/fleetspeak
6 | ConditionPathExists=!/etc/fleetspeak-server/disabled
7 |
8 | [Service]
9 | User=fleetspeak
10 | Group=fleetspeak
11 | ExecStart=/usr/bin/fleetspeak-server --services_config /etc/fleetspeak-server/server.services.config --components_config /etc/fleetspeak-server/server.components.config
12 | Restart=always
13 |
14 | [Install]
15 | WantedBy=multi-user.target
16 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/install:
--------------------------------------------------------------------------------
1 | etc/fleetspeak-server/server.services.config etc/fleetspeak-server
2 | etc/fleetspeak-server/configurator.config etc/fleetspeak-server
3 | usr/bin/fleetspeak-server usr/bin
4 | usr/bin/fleetspeak-config usr/bin
5 | usr/bin/fleetspeak-admin usr/bin
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/postinst:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Post-installation script for the Fleetspeak server deb.
4 | #
5 |
6 | set -e
7 |
8 | # The token below is replaced with shellscript snippets generated
9 | # by debhelper commands. See http://manpages.ubuntu.com/dh_installdeb
10 |
11 | #DEBHELPER#
12 |
13 | case "$1" in
14 | configure)
15 | adduser --system fleetspeak
16 | groupadd --system -f fleetspeak
17 | chown -R fleetspeak:fleetspeak /etc/fleetspeak-server
18 |
19 | # Allow "fleetspeak" user to bind to a low port (443).
20 | setcap 'cap_net_bind_service=+ep' /usr/bin/fleetspeak-server
21 | ;;
22 | esac
23 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | # -*- makefile -*-
3 |
4 | # See this article for ideas re Go packaging in Debian:
5 | # https://vincent.bernat.ch/en/blog/2016-pragmatic-debian-packaging
6 |
7 | # Uncomment this to turn on verbose mode.
8 | # export DH_VERBOSE=1
9 |
10 | %:
11 | dh $@ --with systemd
12 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/etc/fleetspeak-server/server.services.config:
--------------------------------------------------------------------------------
1 | # Fleetspeak server configuration file. This is a text format
2 | # fleetspeak.server.ServerConfig protocol buffer.
3 |
4 | # The primary purpose of this file is to determine where messages for each
5 | # service go. Each 'services' block routes message for a particular service.
6 |
7 | # This example sends GRR messages to a server over GRPC without authentication
8 | # or encryption - it should only be used when the GRR server is bound to
9 | # localhost or otherwise firewalled away from general access.
10 | #services {
11 | # name: "GRR"
12 | # factory: "GRPC"
13 | # config {
14 | # [type.googleapis.com/fleetspeak.grpcservce.Config] {
15 | # target: "localhost:"
16 | # insecure: true
17 | # }
18 | # }
19 | #}
20 |
--------------------------------------------------------------------------------
/fleetspeak/server-pkg-tmpl/usr/share/doc/fleetspeak-server/copyright:
--------------------------------------------------------------------------------
1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: Fleetspeak
3 | Upstream-Contact: GRR Dev
4 | Source: https://github.com/google/fleetspeak
5 |
6 | Files: *
7 | Copyright: 2017-2018 Google
8 | License: Apache-2.0
9 |
--------------------------------------------------------------------------------
/fleetspeak/server-wheel/setup.py:
--------------------------------------------------------------------------------
1 | from optparse import OptionParser
2 | import pathlib
3 | import sys
4 |
5 | from setuptools import setup
6 | from wheel.bdist_wheel import bdist_wheel
7 |
8 |
9 | class BdistWheel(bdist_wheel):
10 | user_options = [
11 | ("platform-name=", None, "Platform name to force."),
12 | ]
13 |
14 | def initialize_options(self):
15 | self.platform_name = None
16 | bdist_wheel.initialize_options(self)
17 |
18 | def finalize_options(self):
19 | bdist_wheel.finalize_options(self)
20 | self.root_is_pure = False
21 |
22 | def get_tag(self):
23 | impl, abi_tag, plat_name = bdist_wheel.get_tag(self)
24 | if self.platform_name is not None:
25 | plat_name = self.platform_name
26 | return "py2.py3", "none", plat_name
27 |
28 |
29 | def GetOptions():
30 | parser = OptionParser()
31 | parser.add_option("--package-root")
32 | parser.add_option("--version")
33 | options, sys.argv[1:] = parser.parse_args()
34 | for option in "package_root", "version":
35 | if not getattr(options, option):
36 | parser.error("--{} is required.".format(option))
37 | return options
38 |
39 |
40 | def DataFiles(prefix_in_pkg, root_dir):
41 | result = []
42 | for path in pathlib.Path(root_dir).glob("**/*"):
43 | if path.is_dir():
44 | continue
45 | relative = path.relative_to(root_dir)
46 | result.append((str(prefix_in_pkg / relative.parent), [str(path)]))
47 | return result
48 |
49 |
50 | options = GetOptions()
51 |
52 | setup(
53 | name="fleetspeak-server-bin",
54 | version=options.version,
55 | packages=[],
56 | cmdclass={
57 | "bdist_wheel": BdistWheel,
58 | },
59 | data_files=DataFiles("fleetspeak-server-bin", options.package_root),
60 | )
61 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/channel/proto/fleetspeak_channel/channel.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.channel;
4 |
5 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/channel/proto/fleetspeak_channel";
6 |
7 | // Optional first message sent through a channel when it is created. It is meant
8 | // to contain info about the process that the other end of the channel might
9 | // find useful.
10 | message StartupData {
11 | // Self-reported PID.
12 | int64 pid = 1;
13 |
14 | // Self-reported service version string.
15 | string version = 2;
16 | }
17 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/clienttestutils/clienttestutils.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package clienttestutils contains utility functions for the client test, in part platform-specific.
16 | package clienttestutils
17 |
18 | import (
19 | "fmt"
20 | "os"
21 | "path/filepath"
22 |
23 | "google.golang.org/protobuf/encoding/prototext"
24 | "google.golang.org/protobuf/proto"
25 |
26 | fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
27 | )
28 |
29 | // WriteSignedServiceConfig saves the given signed config to a test location.
30 | func WriteSignedServiceConfig(dirpath, filename string, cfg *fspb.SignedClientServiceConfig) error {
31 | b, err := proto.Marshal(cfg)
32 | if err != nil {
33 | return fmt.Errorf("unable to serialize signed service config: %v", err)
34 | }
35 |
36 | configPath := filepath.Join(dirpath, filename)
37 | if err := os.WriteFile(configPath, b, 0644); err != nil {
38 | return fmt.Errorf("unable to write signed service config[%s]: %v", configPath, err)
39 | }
40 |
41 | return nil
42 | }
43 |
44 | // WriteServiceConfig saves the given config to a test location.
45 | func WriteServiceConfig(dirpath, filename string, cfg *fspb.ClientServiceConfig) error {
46 | b, err := prototext.Marshal(cfg)
47 | if err != nil {
48 | return err
49 | }
50 |
51 | configPath := filepath.Join(dirpath, filename)
52 | if err := os.WriteFile(configPath, b, 0644); err != nil {
53 | return fmt.Errorf("unable to write service config[%s]: %v", configPath, err)
54 | }
55 |
56 | return nil
57 | }
58 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/config/noop_persistence_handler.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package config
16 |
17 | import (
18 | "errors"
19 |
20 | clpb "github.com/google/fleetspeak/fleetspeak/src/client/proto/fleetspeak_client"
21 | fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
22 | )
23 |
24 | // NoopPersistenceHandler indicates that this client should not attempt
25 | // to maintain state across restarts. If used, every execution will identify
26 | // itself as a new client.
27 | //
28 | // Intended for testing and specialized applications.
29 | type NoopPersistenceHandler struct{}
30 |
31 | // NewNoopPersistenceHandler instantiates a NoopPersistenceHandler.
32 | func NewNoopPersistenceHandler() *NoopPersistenceHandler {
33 | return &NoopPersistenceHandler{}
34 | }
35 |
36 | // ReadState implements PersistenceHandler.
37 | func (*NoopPersistenceHandler) ReadState() (*clpb.ClientState, error) {
38 | return &clpb.ClientState{}, nil
39 | }
40 |
41 | // WriteState implements PersistenceHandler.
42 | func (*NoopPersistenceHandler) WriteState(s *clpb.ClientState) error {
43 | return nil
44 | }
45 |
46 | // ReadCommunicatorConfig implements PersistenceHandler.
47 | func (*NoopPersistenceHandler) ReadCommunicatorConfig() (*clpb.CommunicatorConfig, error) {
48 | return nil, nil
49 | }
50 |
51 | // ReadSignedServices implements PersistenceHandler.
52 | func (*NoopPersistenceHandler) ReadSignedServices() ([]*fspb.SignedClientServiceConfig, error) {
53 | return nil, nil
54 | }
55 |
56 | // ReadServices implements PersistenceHandler.
57 | func (*NoopPersistenceHandler) ReadServices() ([]*fspb.ClientServiceConfig, error) {
58 | return nil, nil
59 | }
60 |
61 | // SaveSignedService implements PersistenceHandler.
62 | func (*NoopPersistenceHandler) SaveSignedService(*fspb.SignedClientServiceConfig) error {
63 | return errors.New("not implemented")
64 | }
65 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/daemonservice/command/command_unix.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build linux || darwin
16 |
17 | package command
18 |
19 | import (
20 | "fmt"
21 | "os"
22 |
23 | "golang.org/x/sys/unix"
24 | )
25 |
26 | func (cmd *Command) softKill() error {
27 | return unix.Kill(cmd.Process.Pid, unix.SIGINT)
28 | }
29 |
30 | func (cmd *Command) kill() error {
31 | return unix.Kill(cmd.Process.Pid, unix.SIGKILL)
32 | }
33 |
34 | func (cmd *Command) addInPipeFDImpl() (*os.File, int, error) {
35 | pr, pw, err := os.Pipe()
36 | if err != nil {
37 | return nil, 0, fmt.Errorf("error in os.Pipe: %v", err)
38 | }
39 |
40 | cmd.ExtraFiles = append(cmd.ExtraFiles, pr)
41 | cmd.filesToClose = append(cmd.filesToClose, pr)
42 |
43 | // Starts with 3.
44 | // See: https://golang.org/pkg/os/exec/#Cmd
45 | fd := len(cmd.ExtraFiles) + 2
46 |
47 | return pw, fd, nil
48 | }
49 |
50 | func (cmd *Command) addOutPipeFDImpl() (*os.File, int, error) {
51 | pr, pw, err := os.Pipe()
52 | if err != nil {
53 | return nil, 0, fmt.Errorf("error in os.Pipe: %v", err)
54 | }
55 |
56 | cmd.ExtraFiles = append(cmd.ExtraFiles, pw)
57 | cmd.filesToClose = append(cmd.filesToClose, pw)
58 |
59 | // Starts with 3.
60 | // See: https://golang.org/pkg/os/exec/#Cmd
61 | fd := len(cmd.ExtraFiles) + 2
62 |
63 | return pr, fd, nil
64 | }
65 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/daemonservice/command/command_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build windows
16 |
17 | package command
18 |
19 | import (
20 | "fmt"
21 | "os"
22 | "syscall"
23 | )
24 |
25 | func (cmd *Command) softKill() error {
26 | return cmd.Kill()
27 | }
28 |
29 | func (cmd *Command) kill() error {
30 | return cmd.Cmd.Process.Kill()
31 | }
32 |
33 | func (cmd *Command) addInPipeFDImpl() (*os.File, int, error) {
34 | pr, pw, err := os.Pipe()
35 | if err != nil {
36 | return nil, 0, fmt.Errorf("error in os.Pipe: %v", err)
37 | }
38 |
39 | fd := pr.Fd()
40 | syscall.SetHandleInformation(syscall.Handle(fd), syscall.HANDLE_FLAG_INHERIT, 1)
41 | cmd.filesToClose = append(cmd.filesToClose, pr)
42 |
43 | if cmd.SysProcAttr == nil {
44 | cmd.SysProcAttr = &syscall.SysProcAttr{}
45 | }
46 | cmd.SysProcAttr.AdditionalInheritedHandles = append(cmd.SysProcAttr.AdditionalInheritedHandles, syscall.Handle(fd))
47 |
48 | return pw, int(fd), nil
49 | }
50 |
51 | func (cmd *Command) addOutPipeFDImpl() (*os.File, int, error) {
52 | pr, pw, err := os.Pipe()
53 | if err != nil {
54 | return nil, 0, fmt.Errorf("error in os.Pipe: %v", err)
55 | }
56 |
57 | fd := pw.Fd()
58 | syscall.SetHandleInformation(syscall.Handle(fd), syscall.HANDLE_FLAG_INHERIT, 1)
59 | cmd.filesToClose = append(cmd.filesToClose, pw)
60 |
61 | if cmd.SysProcAttr == nil {
62 | cmd.SysProcAttr = &syscall.SysProcAttr{}
63 | }
64 | cmd.SysProcAttr.AdditionalInheritedHandles = append(cmd.SysProcAttr.AdditionalInheritedHandles, syscall.Handle(fd))
65 |
66 | return pr, int(fd), nil
67 | }
68 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/daemonservice/daemonservice_oss_test.go:
--------------------------------------------------------------------------------
1 | //go:build !google_internal
2 |
3 | package daemonservice
4 |
5 | import (
6 | "runtime"
7 | "testing"
8 | )
9 |
10 | func testClient(t *testing.T) []string {
11 | if runtime.GOOS == "windows" {
12 | return []string{`testclient\testclient.exe`}
13 | }
14 |
15 | return []string{"testclient/testclient"}
16 | }
17 |
18 | func testClientPY(t *testing.T) []string {
19 | return []string{"python", "-m", "fleetspeak.client_connector.testing.testclient"}
20 | }
21 |
22 | func testClientLauncherPY(t *testing.T) []string {
23 | return []string{"python", "-m", "fleetspeak.client_connector.testing.testclient_launcher"}
24 | }
25 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/daemonservice/execution/execution_oss_test.go:
--------------------------------------------------------------------------------
1 | //go:build !google_internal
2 |
3 | package execution
4 |
5 | import (
6 | "runtime"
7 | "testing"
8 | )
9 |
10 | func testClient(t *testing.T) string {
11 | if runtime.GOOS == "windows" {
12 | return `..\testclient\testclient.exe`
13 | }
14 |
15 | return "../testclient/testclient"
16 | }
17 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/daemonservice/proto/fleetspeak_daemonservice/messages.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.daemonservice;
4 |
5 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/daemonservice/proto/fleetspeak_daemonservice";
6 |
7 | // A fleetspeak.Message with message type "StdOutput" and data type
8 | // StdOutputData is sent by a daemon service to the server when the daemon
9 | // subprocess produces output on stdout or stderr.
10 | message StdOutputData {
11 | // The pid of the daemon process.
12 | int64 pid = 1;
13 |
14 | // The index of this message within the set of messages returned for
15 | // this pid.
16 | int64 message_index = 2;
17 |
18 | bytes stdout = 3;
19 | bytes stderr = 4;
20 | }
21 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/entry/entry.go:
--------------------------------------------------------------------------------
1 | // Package entry provides platform-specific wrappers around the application's
2 | // entry points to manage its lifecycle.
3 | package entry
4 |
5 | import (
6 | "context"
7 | "os"
8 | "time"
9 | )
10 |
11 | // Timeout for shutting down gracefully.
12 | //
13 | // If the [InnerMain] function does not return within this time, the process
14 | // may be shut down ungracefully.
15 | const shutdownTimeout = 10 * time.Second
16 |
17 | // InnerMain is an inner entry function responsible for creating a
18 | // [client.Client] and managing its configuration and lifecycle. It is called by
19 | // [RunMain] which handles platform-specific mechanics to manage the passed
20 | // [Context].
21 | // The [cfgReloadSignals] channel gets a [syscall.SIGHUP] when a config reload
22 | // is requested. We use UNIX conventions here, the Windows layer can send a
23 | // [syscall.SIGHUP] when appropriate.
24 | type InnerMain func(ctx context.Context, cfgReloadSignals <-chan os.Signal) error
25 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/flow/filter.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package flow contains structures and utility method relating to client-server
16 | // flow control configuration.
17 | package flow
18 |
19 | import "sync/atomic"
20 |
21 | const (
22 | lowFiltered int32 = 1 << iota
23 | medFiltered
24 | highFiltered
25 | )
26 |
27 | // Filter is a thread safe data structure which remembers 3 booleans, used to
28 | // indicate which of three priority levels should be filtered. The underlying
29 | // type should be seen as an implementation detail.
30 | type Filter int32
31 |
32 | // NewFilter returns a Filter which is not set to filter anything.
33 | func NewFilter() *Filter {
34 | return new(Filter)
35 | }
36 |
37 | // Set sets the filter bits according to the provided booleans.
38 | func (f *Filter) Set(low, medium, high bool) {
39 | var i int32
40 | if low {
41 | i |= lowFiltered
42 | }
43 | if medium {
44 | i |= medFiltered
45 | }
46 | if high {
47 | i |= highFiltered
48 | }
49 | atomic.StoreInt32((*int32)(f), i)
50 | }
51 |
52 | // Get returns the current state of the filter.
53 | func (f *Filter) Get() (low, medium, high bool) {
54 | i := atomic.LoadInt32((*int32)(f))
55 | return (i&lowFiltered != 0), (i&medFiltered != 0), (i&highFiltered != 0)
56 | }
57 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/flow/filter_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package flow
16 |
17 | import (
18 | "testing"
19 | )
20 |
21 | func TestFilter(t *testing.T) {
22 | f := NewFilter()
23 |
24 | l, m, h := f.Get()
25 | if l != false || m != false || h != false {
26 | t.Errorf("Filter should start (false,false,false), got (%v, %v, %v)", l, m, h)
27 | }
28 |
29 | f.Set(true, false, false)
30 | l, m, h = f.Get()
31 | if l != true || m != false || h != false {
32 | t.Errorf("Filter should be (true,false,false), got (%v, %v, %v)", l, m, h)
33 | }
34 |
35 | f.Set(true, true, false)
36 | l, m, h = f.Get()
37 | if l != true || m != true || h != false {
38 | t.Errorf("Filter should be (true,true,false), got (%v, %v, %v)", l, m, h)
39 | }
40 |
41 | f.Set(true, true, true)
42 | l, m, h = f.Get()
43 | if l != true || m != true || h != true {
44 | t.Errorf("Filter should be (true,true,true), got (%v, %v, %v)", l, m, h)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/generic/config_unix.go:
--------------------------------------------------------------------------------
1 | //go:build linux || darwin
2 |
3 | package generic
4 |
5 | import (
6 | "errors"
7 | "fmt"
8 |
9 | "github.com/google/fleetspeak/fleetspeak/src/client/config"
10 |
11 | gpb "github.com/google/fleetspeak/fleetspeak/src/client/generic/proto/fleetspeak_client_generic"
12 | )
13 |
14 | func makePersistenceHandler(cfg *gpb.Config) (config.PersistenceHandler, error) {
15 | if cfg.PersistenceHandler == nil {
16 | return nil, errors.New("persistence_handler is required")
17 | }
18 | switch h := cfg.PersistenceHandler.(type) {
19 | case *gpb.Config_FilesystemHandler:
20 | return config.NewFilesystemPersistenceHandler(h.FilesystemHandler.ConfigurationDirectory, h.FilesystemHandler.StateFile)
21 | default:
22 | return nil, fmt.Errorf("persistence_handler has unsupported type: %T", cfg.PersistenceHandler)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/generic/config_windows.go:
--------------------------------------------------------------------------------
1 | //go:build windows
2 |
3 | package generic
4 |
5 | import (
6 | "errors"
7 | "fmt"
8 |
9 | "github.com/google/fleetspeak/fleetspeak/src/client/config"
10 |
11 | gpb "github.com/google/fleetspeak/fleetspeak/src/client/generic/proto/fleetspeak_client_generic"
12 | )
13 |
14 | func makePersistenceHandler(cfg *gpb.Config) (config.PersistenceHandler, error) {
15 | if cfg.PersistenceHandler == nil {
16 | return nil, errors.New("persistence_handler is required")
17 | }
18 | switch h := cfg.PersistenceHandler.(type) {
19 | case *gpb.Config_FilesystemHandler:
20 | return config.NewFilesystemPersistenceHandler(h.FilesystemHandler.ConfigurationDirectory, h.FilesystemHandler.StateFile)
21 | case *gpb.Config_RegistryHandler:
22 | return config.NewWindowsRegistryPersistenceHandler(h.RegistryHandler.ConfigurationKey, false)
23 | default:
24 | return nil, fmt.Errorf("persistence_handler has unsupported type: %T", cfg.PersistenceHandler)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/generic/proto/fleetspeak_client_generic/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.client.generic;
4 |
5 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/generic/proto/fleetspeak_client_generic";
6 |
7 | message Config {
8 | // One or more PEM encoded certificates that the client should trust,
9 | // typically a CA certificate specific to the installation.
10 | string trusted_certs = 1;
11 |
12 | // The servers that the client should attempt to connect to in :
13 | // format. E.g. "lazy.com:443", "10.0.0.5:1234"
14 | repeated string server = 2;
15 |
16 | // The client labels that this client should present to the server. Labels
17 | // indicating the client architecture and OS are automatically included.
18 | repeated string client_label = 3;
19 |
20 | oneof persistence_handler {
21 | FilesystemHandler filesystem_handler = 4;
22 | RegistryHandler registry_handler = 5;
23 | }
24 |
25 | // If set, the client will use long running persistent connections, otherwise
26 | // it will make regular short lived polls to the server. Recommended.
27 | bool streaming = 6;
28 |
29 | // If provided, proxy used for connecting to the server.
30 | // The format is a URL.
31 | // See https://golang.org/pkg/net/http/#Transport.Proxy for details.
32 | string proxy = 7;
33 |
34 | // The name of the HTTP header that the client uses to pass its certificate to
35 | // the server frontend for identification. Required only if the server
36 | // frontend is configured to use https_header_checksum_config.
37 | string client_certificate_header = 8;
38 |
39 | // If set, used for SNI and certificate validation.
40 | string server_name = 9;
41 | }
42 |
43 | message FilesystemHandler {
44 | // Where to persist client state, see NewFilesystemPersistenceHandler for
45 | // details:
46 | //
47 | // https://godoc.org/github.com/google/fleetspeak/fleetspeak/src/client/config#FilesystemPersistenceHandler
48 | string configuration_directory = 1;
49 | string state_file = 2;
50 | }
51 |
52 | message RegistryHandler {
53 | // Where to persist client state, see NewWindowsRegistryPersistenceHandler
54 | // for details:
55 | //
56 | // https://github.com/google/fleetspeak/blob/master/fleetspeak/src/client/config/windows_registry_persistence_handler.go
57 | string configuration_key = 1;
58 | }
59 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/https/compression.go:
--------------------------------------------------------------------------------
1 | package https
2 |
3 | import (
4 | "compress/zlib"
5 | "io"
6 | "net/http"
7 |
8 | fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
9 | )
10 |
11 | // BodyWriter is an interface that groups Write, Flush, and Close functions.
12 | type BodyWriter interface {
13 | io.WriteCloser
14 | Flush() error
15 | }
16 |
17 | // CompressingWriter returns a BodyWriter that will compress the data written to
18 | // it with the given compression algorithm and write it to w.
19 | func CompressingWriter(w io.Writer, compression fspb.CompressionAlgorithm) BodyWriter {
20 | switch compression {
21 | case fspb.CompressionAlgorithm_COMPRESSION_DEFLATE:
22 | return zlib.NewWriter(w)
23 | default:
24 | return nopWriteCloseFlusherTo{w}
25 | }
26 | }
27 |
28 | type nopWriteCloseFlusherTo struct {
29 | io.Writer
30 | }
31 |
32 | func (nopWriteCloseFlusherTo) Flush() error {
33 | return nil
34 | }
35 |
36 | func (nopWriteCloseFlusherTo) Close() error {
37 | return nil
38 | }
39 |
40 | // SetContentEncoding sets the Content-Encoding header on req to the appropriate
41 | // value for the given compression algorithm.
42 | func SetContentEncoding(h http.Header, compression fspb.CompressionAlgorithm) {
43 | switch compression {
44 | case fspb.CompressionAlgorithm_COMPRESSION_DEFLATE:
45 | h.Set("Content-Encoding", "deflate")
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/internal/process/process.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package process encapsulates OS-independent process management helpers.
16 | package process
17 |
18 | import (
19 | "os"
20 | )
21 |
22 | // KillByPid causes the Process to exit immediately. It does not wait
23 | // until the Process has actually exited. This only kills the Process
24 | // itself, not any other processes it may have started. If the process
25 | // can't be found at the moment of the call, KillByPid returns nil.
26 | func KillByPid(pid int) error {
27 | p, err := os.FindProcess(pid)
28 | if err != nil {
29 | return nil
30 | }
31 |
32 | return p.Kill()
33 | }
34 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/proto/fleetspeak_client/api.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.client;
4 |
5 | import "google/protobuf/any.proto";
6 |
7 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/proto/fleetspeak_client";
8 |
9 | message ByteBlob {
10 | bytes data = 1;
11 | }
12 |
13 | message APIMessage {
14 | string type = 1;
15 | google.protobuf.Any data = 2;
16 | }
17 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/proto/fleetspeak_client/client.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.client;
4 |
5 | import "fleetspeak/src/common/proto/fleetspeak/common.proto";
6 |
7 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/proto/fleetspeak_client";
8 |
9 | // Parameters used to configure communicator plugins.
10 | message CommunicatorConfig {
11 | // The longest possible wait before attempting to contact the server. The
12 | // communicator may poll sooner if there are messages for the server, of it
13 | // there has been recent communication with the server.
14 | //
15 | // A default of 5 minutes is used if unset.
16 | int32 max_poll_delay_seconds = 2;
17 |
18 | // The longest possible wait before attempting to contact the server when
19 | // there is some data to transmit. The communicator may poll sooner if the
20 | // buffer is full.
21 | //
22 | // A default of 5 seconds is used if unset.
23 | int32 max_buffer_delay_seconds = 3;
24 |
25 | // The minimum time to wait after a failure to reach any server.
26 | //
27 | // A default of 5 minutes is used if unset.
28 | int32 min_failure_delay_seconds = 4;
29 |
30 | // If the communicator is unable to communicate with the server for this long,
31 | // it should kill fleetspeak, in the hope that a restart will fix things.
32 | //
33 | // A default of 7 days is used if unset.
34 | int32 failure_suicide_time_seconds = 5;
35 |
36 | // The compression algorithm to apply on data sent to the server.
37 | //
38 | // No compression is applied if unset.
39 | fleetspeak.CompressionAlgorithm compression = 6;
40 |
41 | // If set, the client will prefer comms with HTTP2 Transport
42 | bool prefer_http2 = 7;
43 | }
44 |
45 | // ClientState contains the state of the client which should be persisted across
46 | // restarts.
47 | message ClientState {
48 | // The client key, normally fixed after first execution. Also defines the
49 | // client's id.
50 | bytes client_key = 1;
51 |
52 | // The most recent sequencing nonce received from the server.
53 | uint64 sequencing_nonce = 7;
54 |
55 | // A set of revoked/blacklisted certificate serial numbers in big endian
56 | // format. Not restricted, but normally at most 20 bytes. (RFC 3280)
57 | repeated bytes revoked_cert_serials = 8;
58 | }
59 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/signer/signer.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package signer defines an interface to add additional signatures to
16 | // communications with the Fleetspeak server.
17 | package signer
18 |
19 | import fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
20 |
21 | // A Signer is given a chance to sign all data sent to the server.
22 | type Signer interface {
23 | // SignContact attempts to produce a signature of data which
24 | // will be included when sending it to the server.
25 | //
26 | // SignContact may return nil if the intended certificate is currently
27 | // unavailable. Otherwise it should return a proto with all fields set.
28 | SignContact(data []byte) *fspb.Signature
29 | }
30 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/socketservice/client/proxy_unix.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build linux || darwin
16 |
17 | package client
18 |
19 | import (
20 | "net"
21 | "time"
22 |
23 | log "github.com/golang/glog"
24 | "github.com/google/fleetspeak/fleetspeak/src/client/channel"
25 | "github.com/google/fleetspeak/fleetspeak/src/client/socketservice/checks"
26 | )
27 |
28 | // buildChannel is almost a channel.Builder, meant to be wrapped to become one
29 | // once socketPath is known.
30 | func buildChannel(socketPath string) (*channel.Channel, func()) {
31 | // Try once per second until the fleetspeak server is available.
32 | var err error
33 | var conn *net.UnixConn
34 |
35 | retryDelay := time.Second
36 | for {
37 | if err = checks.CheckSocketFile(socketPath); err != nil {
38 | log.Warningf("failure checking perms of [%s], will retry: %v", socketPath, err)
39 | } else if conn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: socketPath, Net: "unix"}); err != nil {
40 | log.Warningf("failed to connect to [%s], will retry: %v", socketPath, err)
41 | } else {
42 | log.Infof("connected to [%s]", socketPath)
43 | return channel.New(conn, conn), func() {
44 | // Because it is a socket, this is sufficient to terminate any pending
45 | // I/O operations.
46 | conn.Close()
47 | }
48 | }
49 | time.Sleep(retryDelay)
50 | retryDelay = backOffChannelRetryDelay(retryDelay)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/socketservice/client/proxy_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build windows
16 |
17 | package client
18 |
19 | import (
20 | "net"
21 | "time"
22 |
23 | log "github.com/golang/glog"
24 | "github.com/google/fleetspeak/fleetspeak/src/client/channel"
25 | "github.com/google/fleetspeak/fleetspeak/src/client/socketservice/checks"
26 | "github.com/google/fleetspeak/fleetspeak/src/windows/wnixsocket"
27 | )
28 |
29 | // buildChannel is almost a channel.Builder, meant to be wrapped to become one
30 | // once socketPath is known.
31 | func buildChannel(socketPath string) (*channel.Channel, func()) {
32 | // Try once per second until the fleetspeak server is available.
33 | var err error
34 | var conn net.Conn
35 |
36 | retryDelay := time.Second
37 | for {
38 | if err = checks.CheckSocketFile(socketPath); err != nil {
39 | log.Warningf("Failure checking perms of [%s], will retry: %v", socketPath, err)
40 | } else if conn, err = wnixsocket.Dial(socketPath, time.Second); err != nil {
41 | log.Warningf("Failed to connect to [%s], will retry: %v", socketPath, err)
42 | } else {
43 | log.Infof("Connected to [%s]", socketPath)
44 |
45 | return channel.New(conn, conn), func() {
46 | // Because it is a socket, this is sufficient to terminate any pending
47 | // I/O operations.
48 | conn.Close()
49 | }
50 | }
51 | time.Sleep(retryDelay)
52 | retryDelay = backOffChannelRetryDelay(retryDelay)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/socketservice/proto/fleetspeak_socketservice/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.socketservice;
4 |
5 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/socketservice/proto/fleetspeak_socketservice";
6 |
7 | // The configuration information expected by socketservice.Factory in
8 | // ClientServiceConfig.config.
9 | message Config {
10 | // The given api_proxy_path may be an arbitrary filesystem path and will be
11 | // used to pair the daemon service with its non-child client process.
12 | //
13 | // On Unix in particular, a Unix socket will be created at this path and used
14 | // for communication between FS and the client.
15 | //
16 | // Side note: FS requires the proxy's parent directory's perms to be 0700.
17 | // If the parent directory doesn't exist, FS will mkdir -p it with perms set
18 | // to 0700.
19 | string api_proxy_path = 1;
20 |
21 | // By default, socket services report resource usage every 10 minutes. This
22 | // flag disables this if set.
23 | bool disable_resource_monitoring = 2;
24 |
25 | // How many samples to aggregate into a report when monitoring resource usage.
26 | // If unset, defaults to 20.
27 | int32 resource_monitoring_sample_size = 3;
28 |
29 | // How long to wait between resource monitoring samples. If unset, defaults to
30 | // 30 seconds.
31 | int32 resource_monitoring_sample_period_seconds = 4;
32 | }
33 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/socketservice/socketservice_oss_test.go:
--------------------------------------------------------------------------------
1 | //go:build !google_internal
2 |
3 | package socketservice
4 |
5 | import "testing"
6 |
7 | func testClient(t *testing.T) string {
8 | _ = t // intentionally unused
9 | return "testclient/testclient"
10 | }
11 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/socketservice/socketservice_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build windows
16 |
17 | package socketservice
18 |
19 | import (
20 | "fmt"
21 | "net"
22 | "os"
23 | "path/filepath"
24 |
25 | log "github.com/golang/glog"
26 |
27 | "github.com/google/fleetspeak/fleetspeak/src/client/socketservice/checks"
28 | "github.com/google/fleetspeak/fleetspeak/src/windows/wnixsocket"
29 | "github.com/hectane/go-acl"
30 | )
31 |
32 | func listen(socketPath string) (net.Listener, error) {
33 | parent := filepath.Dir(socketPath)
34 |
35 | // Ensure that the parent directory exists. wnixsocket.Listen ensures the
36 | // socket file exists and is truncated.
37 | stat, err := os.Lstat(parent)
38 | if err != nil && !os.IsNotExist(err) {
39 | return nil, fmt.Errorf("os.Lstat failed: %v", err)
40 | }
41 | if err == nil {
42 | log.Infof("wnix socket parent %v already exists (IsDir: %v)", parent, stat.Mode().IsDir())
43 | }
44 |
45 | if err := os.MkdirAll(parent, 0); err != nil {
46 | return nil, fmt.Errorf("os.MkdirAll failed: %v", err)
47 | }
48 |
49 | // MkdirAll doesn't set mode as expected on Windows, so we make
50 | // sure with Chmod. Note that os.Chmod also doesn't work as expected, so
51 | // we use go-acl.
52 | if err := acl.Chmod(parent, 0700); err != nil {
53 | return nil, fmt.Errorf("failed to chmod a Wnix domain listener's parent directory: %v", err)
54 | }
55 |
56 | l, err := wnixsocket.Listen(socketPath)
57 | if err != nil {
58 | return nil, fmt.Errorf("failed to create a Wnix domain listener: %v", err)
59 | }
60 |
61 | if err := checks.CheckSocketFile(socketPath); err != nil {
62 | return nil, fmt.Errorf("CheckSocketFile(...): %v", err)
63 | }
64 |
65 | return l, nil
66 | }
67 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/stdinservice/proto/fleetspeak_stdinservice/config.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.stdinservice;
4 |
5 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/stdinservice/proto/fleetspeak_stdinservice";
6 |
7 | // The configuration information expected by stdinservice.Factory
8 | // in ClientServiceConfig.config.
9 | message Config {
10 | string cmd = 1;
11 | }
12 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/stdinservice/proto/fleetspeak_stdinservice/messages.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.stdinservice;
4 |
5 | import "google/protobuf/timestamp.proto";
6 |
7 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/client/stdinservice/proto/fleetspeak_stdinservice";
8 |
9 | message InputMessage {
10 | // The data to be forwarded to the service.
11 | bytes input = 1;
12 |
13 | // Command line arguments.
14 | repeated string args = 2;
15 | }
16 |
17 | message OutputMessage {
18 | bytes stdout = 1;
19 | bytes stderr = 2;
20 |
21 | // When the message was generated.
22 | google.protobuf.Timestamp timestamp = 4;
23 |
24 | reserved 3;
25 | }
26 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/watchdog/watchdog_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package watchdog
16 |
17 | import (
18 | "os"
19 | "testing"
20 | "time"
21 |
22 | "github.com/google/fleetspeak/fleetspeak/src/comtesting"
23 | )
24 |
25 | func TestCreate(t *testing.T) {
26 | w := MakeWatchdog("asdf", "asdf", time.Second, true)
27 | w.Stop()
28 | }
29 |
30 | func TestReset(t *testing.T) {
31 | w := MakeWatchdog("asdf", "asdf", time.Second, true)
32 | defer w.Stop()
33 | for range 5 {
34 | time.Sleep(2 * time.Second)
35 | w.Reset()
36 | }
37 | }
38 |
39 | func TestDump(t *testing.T) {
40 | dir, fin := comtesting.GetTempDir("TestDump")
41 | defer fin()
42 |
43 | w := MakeWatchdog(dir, "TestTimer", time.Second, false)
44 | defer w.Stop()
45 |
46 | time.Sleep(6500 * time.Millisecond)
47 |
48 | files, err := os.ReadDir(dir)
49 | if err != nil {
50 | t.Fatal(err)
51 | }
52 | if len(files) != 1 {
53 | t.Fatalf("Expected 1 file, but found %d", len(files))
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/watchdog/watchdog_unix.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build linux || darwin
16 |
17 | package watchdog
18 |
19 | const DefaultDir = "/tmp"
20 |
--------------------------------------------------------------------------------
/fleetspeak/src/client/watchdog/watchdog_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build windows
16 |
17 | package watchdog
18 |
19 | const DefaultDir = `C:\Windows\Temp`
20 |
--------------------------------------------------------------------------------
/fleetspeak/src/common/anypbtest/anypbtest.go:
--------------------------------------------------------------------------------
1 | // Copyright 2024 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package anypbtest offers test helpers for working with AnyPb protos.
16 | package anypbtest
17 |
18 | import (
19 | "testing"
20 |
21 | "google.golang.org/protobuf/proto"
22 | anypb "google.golang.org/protobuf/types/known/anypb"
23 | )
24 |
25 | // New creates a new anypb.Any, failing the test on error.
26 | func New(t *testing.T, msg proto.Message) *anypb.Any {
27 | t.Helper()
28 |
29 | a, err := anypb.New(msg)
30 | if err != nil {
31 | t.Fatalf("anypb.New(%+v): %v", msg, err)
32 | }
33 | return a
34 | }
35 |
--------------------------------------------------------------------------------
/fleetspeak/src/common/proto/fleetspeak_monitoring/resource.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.monitoring;
4 |
5 | import "google/protobuf/timestamp.proto";
6 |
7 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak_monitoring";
8 |
9 | // Contains resource-usage metrics for Fleetspeak clients. The stats are
10 | // arrived at by aggregating raw data retrieved from the OS.
11 | // CPU-usage is in milliseconds per second, and memory usage is in bytes.
12 | message AggregatedResourceUsage {
13 | double mean_user_cpu_rate = 1;
14 | double max_user_cpu_rate = 2;
15 | double mean_system_cpu_rate = 3;
16 | double max_system_cpu_rate = 4;
17 | double mean_resident_memory = 5;
18 | int64 max_resident_memory = 6;
19 | int32 max_num_fds = 7;
20 | double mean_num_fds = 8;
21 | }
22 |
23 | // A fleetspeak.Message with message type "ResourceUsage" is sent regularly by
24 | // the system and daemon services to the server, to report the performance of
25 | // processes.
26 | //
27 | // Next tag: 9
28 | message ResourceUsageData {
29 | // Name of the client service that resource usage is charged/attributed to
30 | // e.g 'system' for the system Fleetspeak service, or the name of a daemon
31 | // service as specified in its config.
32 | string scope = 1;
33 |
34 | int64 pid = 2;
35 |
36 | // The self reported service/service binary version.
37 | string version = 8;
38 |
39 | // Time when the process was started by Fleetspeak.
40 | google.protobuf.Timestamp process_start_time = 3;
41 |
42 | // Corresponds to when computation of the resource-usage data was finalized.
43 | google.protobuf.Timestamp data_timestamp = 4;
44 |
45 | AggregatedResourceUsage resource_usage = 5;
46 |
47 | // Optional debug info for the process.
48 | string debug_status = 6;
49 |
50 | // If true, indicates that the process has terminated, and that this is
51 | // the final resource-usage report for that process.
52 | bool process_terminated = 7;
53 | }
54 |
55 | // Sent by clients when a service gets killed by Fleetspeak, e.g. for using
56 | // too much memory.
57 | message KillNotification {
58 | string service = 1;
59 |
60 | int64 pid = 2;
61 |
62 | // The self-reported version of the service.
63 | string version = 3;
64 |
65 | // Time when the process was started by Fleetspeak.
66 | google.protobuf.Timestamp process_start_time = 4;
67 |
68 | // Time when the process was killed by Fleetspeak.
69 | google.protobuf.Timestamp killed_when = 5;
70 |
71 | enum Reason {
72 | UNSPECIFIED = 0;
73 | HEARTBEAT_FAILURE = 1;
74 | MEMORY_EXCEEDED = 2;
75 | }
76 | Reason reason = 6;
77 | }
78 |
--------------------------------------------------------------------------------
/fleetspeak/src/common/should/never_oss.go:
--------------------------------------------------------------------------------
1 | // Copyright 2024 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build !google_internal
16 |
17 | // Package should lets callers indicate impossible conditions from the code.
18 | //
19 | // It is a lightweight way to make these impossible conditions observable,
20 | // when it is hooked up with an appropriate monitoring framework.
21 | package should
22 |
23 | // Never indicates that the given condition should never (or seldomly) happen.
24 | //
25 | // Callers should only pass a fixed set of strings to Never(),
26 | // to avoid a state explosion in monitoring counters.
27 | func Never(condition string) {
28 | // Unfortunately empty in the open source version.
29 | }
30 |
--------------------------------------------------------------------------------
/fleetspeak/src/comtesting/tempdir.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package comtesting
16 |
17 | import (
18 | "fmt"
19 | "os"
20 |
21 | log "github.com/golang/glog"
22 | )
23 |
24 | var tempDir string
25 |
26 | // GetTempDir creates and returns the name of a temporary directory. Multiple
27 | // calls will return the same name. It uses the name of the test that is being
28 | // run as part of the name of the directory.
29 | //
30 | // The second returned value is a platform-specific cleanup function.
31 | // This is particularly useful on Windows, where the current user's homedir
32 | // can be returned as the temp dir, and gets cluttered quickly.
33 | func GetTempDir(testName string) (string, func()) {
34 | if tempDir != "" {
35 | return tempDir, cleanupTempDir
36 | }
37 |
38 | tempDir = os.Getenv("TEST_TMPDIR")
39 |
40 | if tempDir == "" {
41 | d, err := os.MkdirTemp("", testName+"_")
42 | if err != nil {
43 | panic(fmt.Sprintf("Unable to create temp directory: %v", err))
44 | }
45 | tempDir = d
46 | }
47 | log.Infof("Created temp directory: %s", tempDir)
48 | return tempDir, cleanupTempDir
49 | }
50 |
--------------------------------------------------------------------------------
/fleetspeak/src/comtesting/tempdir_unix.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build linux || darwin
16 |
17 | package comtesting
18 |
19 | func cleanupTempDir() {
20 | tempDir = ""
21 | }
22 |
--------------------------------------------------------------------------------
/fleetspeak/src/comtesting/tempdir_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build windows
16 |
17 | package comtesting
18 |
19 | import (
20 | "os"
21 |
22 | log "github.com/golang/glog"
23 | )
24 |
25 | func cleanupTempDir() {
26 | if tempDir == "" {
27 | return
28 | }
29 |
30 | if err := os.RemoveAll(tempDir); err != nil {
31 | log.Errorf("Failed to cleanup temp dir; os.RemoveAll(%q): %v", tempDir, err)
32 | return
33 | }
34 |
35 | tempDir = ""
36 | }
37 |
--------------------------------------------------------------------------------
/fleetspeak/src/config/server/config.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package serer
16 | package server
17 |
18 | import (
19 | "errors"
20 | "fmt"
21 | "os"
22 |
23 | "google.golang.org/protobuf/encoding/prototext"
24 |
25 | cpb "github.com/google/fleetspeak/fleetspeak/src/config/proto/fleetspeak_config"
26 | )
27 |
28 | // WriteConfig validates and then writes a server component configuration.
29 | func WriteConfig(cfg *cpb.Config, certPEM, keyPEM []byte) error {
30 | if cfg.ServerComponentConfigurationFile == "" {
31 | return errors.New("server_component_configuration_file is required")
32 | }
33 |
34 | cc := cfg.ComponentsConfig
35 | if cc == nil {
36 | return errors.New("components_config is required")
37 | }
38 | if cc.HttpsConfig == nil {
39 | return errors.New("components_config.https_config is required")
40 | }
41 | if cc.HttpsConfig.ListenAddress == "" {
42 | return errors.New("components_config.https_config.listen_address is required")
43 | }
44 | cc.HttpsConfig.Certificates = string(certPEM)
45 | cc.HttpsConfig.Key = string(keyPEM)
46 |
47 | b, err := prototext.Marshal(cc)
48 | if err != nil {
49 | return fmt.Errorf("failed to marshal server component configuration: %v", err)
50 | }
51 | err = os.WriteFile(cfg.ServerComponentConfigurationFile, b, 0600)
52 | if err != nil {
53 | return fmt.Errorf("failed to write server component configuration file [%s]: %v", cfg.ServerComponentConfigurationFile, err)
54 | }
55 |
56 | return nil
57 | }
58 |
--------------------------------------------------------------------------------
/fleetspeak/src/e2etesting/balancer/balancer.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "io"
7 | "log"
8 | "math/rand"
9 | "net"
10 | "os"
11 | "strings"
12 | "time"
13 |
14 | "github.com/google/fleetspeak/fleetspeak/src/e2etesting/balancer/proxyproto"
15 | )
16 |
17 | var (
18 | serversFile = flag.String("servers_file", "", "File with server hosts")
19 | serverFrontendAddr = flag.String("frontend_address", "", "Frontend address for clients to connect")
20 | useProxyProto = flag.Bool("use_proxy_proto", true, "Whether to forward client information using proxy proto")
21 | )
22 |
23 | func copy(wc io.WriteCloser, r io.Reader) {
24 | defer wc.Close()
25 | io.Copy(wc, r)
26 | }
27 |
28 | func run() error {
29 | dat, err := os.ReadFile(*serversFile)
30 | if err != nil {
31 | return fmt.Errorf("Failed to read serversFile: %v", err)
32 | }
33 | serverHosts := strings.Fields(string(dat))
34 | if len(serverHosts) == 0 {
35 | return fmt.Errorf("No server hosts were provided")
36 | }
37 |
38 | ln, err := net.Listen("tcp", *serverFrontendAddr)
39 | if err != nil {
40 | return fmt.Errorf("Failed to bind: %v", err)
41 | }
42 | log.Printf("Load balancer started on %v\n", *serverFrontendAddr)
43 |
44 | for {
45 | lbConn, err := ln.Accept()
46 | if err != nil {
47 | return fmt.Errorf("Failed to accept connection: %v", err)
48 | }
49 | var serverAddr string
50 | var serverConn net.Conn
51 | retriesLeft := 10
52 | for {
53 | serverAddr = serverHosts[rand.Int()%len(serverHosts)]
54 | serverConn, err = net.Dial("tcp", serverAddr)
55 | if err != nil {
56 | log.Printf("Failed to connect to server (%v): %v, retrying...\n", serverAddr, err)
57 | retriesLeft--
58 | if retriesLeft < 0 {
59 | return fmt.Errorf("Maximum number of retries exceeded - no active servers were found")
60 | }
61 | time.Sleep(time.Second * 2)
62 | } else {
63 | break
64 | }
65 | }
66 | log.Printf("Connection accepted, server: %v\n", serverAddr)
67 | if *useProxyProto {
68 | err = proxyproto.WriteFirstProxyMessage(serverConn, lbConn.RemoteAddr().String(), serverAddr)
69 | if err != nil {
70 | return err
71 | }
72 | }
73 | go copy(serverConn, lbConn)
74 | go copy(lbConn, serverConn)
75 | }
76 | }
77 |
78 | func main() {
79 | flag.Parse()
80 | err := run()
81 | if err != nil {
82 | fmt.Printf("Load balancer failed: %v\n", err)
83 | os.Exit(1)
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/fleetspeak/src/e2etesting/balancer/proxyproto/proxyproto.go:
--------------------------------------------------------------------------------
1 | package proxyproto
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "net"
7 | "strconv"
8 |
9 | proxyproto "github.com/pires/go-proxyproto"
10 | )
11 |
12 | func splitHostPort(addr string) (net.IP, uint16, error) {
13 | ta, err := net.ResolveTCPAddr("tcp", addr)
14 | if err == nil {
15 | return ta.IP, uint16(ta.Port), nil
16 | }
17 | hostStr, portStr, err := net.SplitHostPort(addr)
18 | if err != nil {
19 | return nil, 0, err
20 | }
21 | host := net.ParseIP(hostStr)
22 | if host == nil {
23 | return nil, 0, fmt.Errorf("Failed to parse IP")
24 | }
25 | port, err := strconv.Atoi(portStr)
26 | if err != nil {
27 | return nil, 0, fmt.Errorf("Failed to parse port: %v", err)
28 | }
29 | return host, uint16(port), nil
30 | }
31 |
32 | func WriteFirstProxyMessage(w io.Writer, srcAddr, dstAddr string) error {
33 | srcHost, srcPort, err := splitHostPort(srcAddr)
34 | if err != nil {
35 | return fmt.Errorf("Failed to parse source (client) address: %v", err)
36 | }
37 | dstHost, dstPort, err := splitHostPort(dstAddr)
38 | if err != nil {
39 | return fmt.Errorf("Failed to parse destination (server) address: %v", err)
40 | }
41 | header := proxyproto.Header{
42 | Version: 1,
43 | TransportProtocol: proxyproto.TCPv4,
44 | SourceAddr: &net.TCPAddr{IP: srcHost, Port: int(srcPort)},
45 | DestinationAddr: &net.TCPAddr{IP: dstHost, Port: int(dstPort)},
46 | }
47 | _, err = header.WriteTo(w)
48 | if err != nil {
49 | return fmt.Errorf("Failed to write Proxy header: %v", err)
50 | }
51 | return nil
52 | }
53 |
--------------------------------------------------------------------------------
/fleetspeak/src/e2etesting/frr_master_server_main/frr_master_server_main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "net"
7 | "os"
8 |
9 | frr "github.com/google/fleetspeak/fleetspeak/src/inttesting/frr"
10 | fgrpc "github.com/google/fleetspeak/fleetspeak/src/inttesting/frr/proto/fleetspeak_frr"
11 | sgrpc "github.com/google/fleetspeak/fleetspeak/src/server/proto/fleetspeak_server"
12 | "google.golang.org/grpc"
13 | "google.golang.org/grpc/credentials/insecure"
14 | )
15 |
16 | var (
17 | listenAddr = flag.String("listen_address", "localhost:6059", "Address for clients to connect")
18 | adminAddr = flag.String("admin_address", "localhost:6061", "Fleetspeak server admin address")
19 | )
20 |
21 | // StartMasterServer starts FRR Master Server listening to listenAddr
22 | func StartMasterServer(listenAddr, adminAddr string) error {
23 | conn, err := grpc.NewClient(adminAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
24 | if err != nil {
25 | return fmt.Errorf("Unable to connect to FS server: %v", err)
26 | }
27 | defer conn.Close()
28 |
29 | ms := frr.NewMasterServer(sgrpc.NewAdminClient(conn))
30 | gms := grpc.NewServer()
31 | fgrpc.RegisterMasterServer(gms, ms)
32 | ad, err := net.ResolveTCPAddr("tcp", listenAddr)
33 | if err != nil {
34 | return fmt.Errorf("Unable to resolve tcp address: %v", err)
35 | }
36 | tl, err := net.ListenTCP("tcp", ad)
37 | if err != nil {
38 | return fmt.Errorf("Unable to start listening TCP: %v", err)
39 | }
40 | defer gms.Stop()
41 | gms.Serve(tl)
42 | return nil
43 | }
44 |
45 | func main() {
46 | flag.Parse()
47 | err := StartMasterServer(*listenAddr, *adminAddr)
48 | if err != nil {
49 | fmt.Println(err)
50 | os.Exit(1)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/fleetspeak/src/e2etesting/localtesting/end_to_end_test.go:
--------------------------------------------------------------------------------
1 | package localtesting_test
2 |
3 | import (
4 | "flag"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/google/fleetspeak/fleetspeak/src/e2etesting/setup"
10 | "github.com/google/fleetspeak/fleetspeak/src/e2etesting/tests"
11 | )
12 |
13 | var (
14 | mysqlAddress = flag.String("mysql_address", "", "MySQL server address")
15 | mysqlDatabase = flag.String("mysql_database", "", "MySQL database name to use")
16 | mysqlUsername = flag.String("mysql_username", "", "MySQL username to use")
17 | mysqlPassword = flag.String("mysql_password", "", "MySQL password to use")
18 | numClients = flag.Int("num_clients", 3, "Number of clients to test")
19 | numServers = flag.Int("num_servers", 2, "Number of servers to test")
20 | )
21 |
22 | func parseFlags() {
23 | flag.Parse()
24 | for flagVar, envVarName := range map[*string]string{
25 | mysqlAddress: "MYSQL_TEST_ADDR",
26 | mysqlUsername: "MYSQL_TEST_USER",
27 | mysqlPassword: "MYSQL_TEST_PASS",
28 | mysqlDatabase: "MYSQL_TEST_E2E_DB",
29 | } {
30 | val := os.Getenv(envVarName)
31 | if len(val) > 0 {
32 | *flagVar = val
33 | }
34 | }
35 | }
36 |
37 | // Test end to end
38 | func TestLocalEndToEnd(t *testing.T) {
39 | parseFlags()
40 | if *mysqlAddress == "" {
41 | t.Skip("Mysql address not provided")
42 | }
43 | if *mysqlUsername == "" {
44 | t.Skip("Mysql user not provided")
45 | }
46 | if *mysqlDatabase == "" {
47 | t.Skip("Mysql database for end-to-end testing not provided")
48 | }
49 |
50 | wd, err := os.Getwd()
51 | if err != nil {
52 | t.Fatalf("Failed to get working directory: %v", err)
53 | }
54 | for range 4 {
55 | wd = filepath.Dir(wd)
56 | }
57 | err = os.Chdir(wd)
58 | if err != nil {
59 | t.Fatalf("Failed to change directory: %v", err)
60 | }
61 |
62 | frontendAddress := "localhost:6000"
63 | msAddress := "localhost:6059"
64 |
65 | clientIDs := setup.ConfigureAndStart(t, setup.MysqlCredentials{
66 | Host: *mysqlAddress,
67 | Password: *mysqlPassword,
68 | Username: *mysqlUsername,
69 | Database: *mysqlDatabase,
70 | }, frontendAddress, msAddress, *numServers, *numClients)
71 |
72 | tests.RunTests(t, msAddress, clientIDs)
73 | }
74 |
--------------------------------------------------------------------------------
/fleetspeak/src/inttesting/integration_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package integration_test runs integrationtest against the sqlite datastore.
16 | package integration_test
17 |
18 | import (
19 | "path/filepath"
20 | "testing"
21 |
22 | "github.com/google/fleetspeak/fleetspeak/src/inttesting/integrationtest"
23 | "github.com/google/fleetspeak/fleetspeak/src/server/sqlite"
24 | )
25 |
26 | func mustMakeDatastore(t *testing.T) *sqlite.Datastore {
27 | t.Helper()
28 |
29 | ds, err := sqlite.MakeDatastore(filepath.Join(t.TempDir(), "DataStore.sqlite"))
30 | if err != nil {
31 | t.Fatalf("sqlite.MakeDatastore: %v", err)
32 | }
33 | t.Cleanup(func() {
34 | err := ds.Close()
35 | if err != nil {
36 | t.Errorf("Closing SQLite datastore: %v", err)
37 | }
38 | })
39 | return ds
40 | }
41 |
42 | func TestFRRIntegration(t *testing.T) {
43 | ds := mustMakeDatastore(t)
44 | integrationtest.FRRIntegrationTest(t, ds, false)
45 | }
46 |
47 | func TestCloneHandling(t *testing.T) {
48 | ds := mustMakeDatastore(t)
49 | integrationtest.CloneHandlingTest(t, ds)
50 | }
51 |
52 | func TestFRRIntegrationStreaming(t *testing.T) {
53 | ds := mustMakeDatastore(t)
54 | integrationtest.FRRIntegrationTest(t, ds, true)
55 | }
56 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/components/authorizer/authorizer.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package authorizer provide generic implementations and utility methods
16 | // for Fleetspeak's authorizer component type.
17 | package authorizer
18 |
19 | import (
20 | "net"
21 |
22 | "github.com/google/fleetspeak/fleetspeak/src/server/authorizer"
23 |
24 | fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
25 | )
26 |
27 | // LabelFilter is an authorizer.Authorizer which refuses connections from
28 | // clients that do not have a specific label.
29 | type LabelFilter struct {
30 | Label string
31 | }
32 |
33 | // Allow1 implements Authorizer.
34 | func (f LabelFilter) Allow1(net.Addr) bool { return true }
35 |
36 | // Allow2 implements Authorizer.
37 | func (f LabelFilter) Allow2(_ net.Addr, i authorizer.ContactInfo) bool {
38 | if f.Label == "" {
39 | return true
40 | }
41 | for _, l := range i.ClientLabels {
42 | if l == f.Label {
43 | return true
44 | }
45 | }
46 | return false
47 | }
48 |
49 | // Allow3 implements Authorizer.
50 | func (f LabelFilter) Allow3(net.Addr, authorizer.ContactInfo, authorizer.ClientInfo) bool {
51 | return true
52 | }
53 |
54 | // Allow4 implements Authorizer.
55 | func (f LabelFilter) Allow4(net.Addr, authorizer.ContactInfo, authorizer.ClientInfo, []authorizer.SignatureInfo) (bool, *fspb.ValidationInfo) {
56 | return true, nil
57 | }
58 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/components/components_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package components
16 |
17 | import (
18 | "testing"
19 |
20 | cpb "github.com/google/fleetspeak/fleetspeak/src/server/components/proto/fleetspeak_components"
21 | )
22 |
23 | func TestValidation(t *testing.T) {
24 | for _, tc := range []struct {
25 | cfg *cpb.Config
26 | wantErr string
27 | }{
28 | {
29 | cfg: &cpb.Config{},
30 | wantErr: "mysql_data_source_name OR spanner_database_name is required",
31 | },
32 | {
33 | cfg: &cpb.Config{
34 | MysqlDataSourceName: "fs:seecret@tcp(localhost:1234)/fsdb",
35 | HttpsConfig: &cpb.HttpsConfig{
36 | ListenAddress: "localhost:443",
37 | },
38 | },
39 | wantErr: "https_config requires listen_address, certificates and key",
40 | },
41 | {
42 | cfg: &cpb.Config{
43 | MysqlDataSourceName: "fs:seecret@tcp(localhost:1234)/fsdb",
44 | HttpsConfig: &cpb.HttpsConfig{
45 | ListenAddress: "localhost:443",
46 | Certificates: "<>",
47 | Key: "<>",
48 | },
49 | AdminConfig: &cpb.AdminConfig{},
50 | },
51 | wantErr: "admin_config.listen_address can't be empty",
52 | },
53 | } {
54 | _, err := MakeComponents(tc.cfg)
55 | if err == nil || err.Error() != tc.wantErr {
56 | t.Errorf("Expected error message [%v], got [%v]", tc.wantErr, err)
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/components/https/proxy.go:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package https provides generic implementations and utility methods for
16 | // Fleetspeak https communication component type.
17 | package https
18 |
19 | import (
20 | "bufio"
21 | "fmt"
22 | "net"
23 |
24 | log "github.com/golang/glog"
25 |
26 | proxyproto "github.com/pires/go-proxyproto"
27 | )
28 |
29 | // ProxyListener wraps a net.Listener and adapts the perceived source of the connection
30 | // to be that provided by the PROXY protocol header string. Should be used only when the
31 | // server is behind a load balancer which implements the PROXY protocol.
32 | //
33 | // https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
34 | type ProxyListener struct {
35 | net.Listener
36 | }
37 |
38 | func (l *ProxyListener) Accept() (net.Conn, error) {
39 | c, err := l.Listener.Accept()
40 | if err != nil {
41 | return c, err
42 | }
43 | r := bufio.NewReader(c)
44 | h, err := proxyproto.Read(r)
45 | if err == proxyproto.ErrNoProxyProtocol {
46 | log.Warningf("Received connection from %v without proxy header.", c.RemoteAddr())
47 | return &proxyConn{
48 | Conn: c,
49 | reader: r,
50 | remote: c.RemoteAddr(),
51 | }, nil
52 | }
53 | if err != nil {
54 | return nil, fmt.Errorf("error parsing proxy header: %v", err)
55 | }
56 | return &proxyConn{
57 | Conn: c,
58 | reader: r,
59 | remote: h.SourceAddr,
60 | }, nil
61 | }
62 |
63 | type proxyConn struct {
64 | net.Conn
65 | reader *bufio.Reader
66 | remote net.Addr
67 | }
68 |
69 | func (c *proxyConn) Read(b []byte) (int, error) {
70 | return c.reader.Read(b)
71 | }
72 |
73 | func (c *proxyConn) RemoteAddr() net.Addr {
74 | return c.remote
75 | }
76 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/components/notifications/http_test.go:
--------------------------------------------------------------------------------
1 | package notifications
2 |
3 | import (
4 | "context"
5 | "reflect"
6 | "sync"
7 | "testing"
8 | "time"
9 |
10 | log "github.com/golang/glog"
11 |
12 | "github.com/google/fleetspeak/fleetspeak/src/common"
13 | "github.com/google/fleetspeak/fleetspeak/src/server/notifications"
14 | )
15 |
16 | func TestListenNotify(t *testing.T) {
17 | var l notifications.Listener
18 | l = &HttpListener{
19 | BindAddress: "localhost:",
20 | }
21 | c, err := l.Start()
22 | if err != nil {
23 | t.Fatalf("Failed to start listener: %v", err)
24 | }
25 | defer l.Stop()
26 | log.Infof("Started [locahost:] listener, reports address: %v", l.Address())
27 |
28 | mtx := &sync.Mutex{}
29 | var gotIDs []common.ClientID
30 | go func() {
31 | for id := range c {
32 | mtx.Lock()
33 | gotIDs = append(gotIDs, id)
34 | mtx.Unlock()
35 | }
36 | }()
37 |
38 | n := HttpNotifier{}
39 | id1, _ := common.StringToClientID("0000000000000001")
40 | id2, _ := common.StringToClientID("0000000000000002")
41 |
42 | for _, id := range []common.ClientID{id1, id2} {
43 | if err := n.NewMessageForClient(context.Background(), l.Address(), id); err != nil {
44 | t.Errorf("Unable to send notification for client: %v", err)
45 | }
46 | }
47 |
48 | // TODO: Clean up concurrency in this test! We are not waiting for results correctly.
49 | time.Sleep(500 * time.Millisecond)
50 |
51 | mtx.Lock()
52 | defer mtx.Unlock()
53 | if !reflect.DeepEqual(gotIDs, []common.ClientID{id1, id2}) {
54 | t.Errorf("Unexpected ids received got: %v want: %v", gotIDs, []common.ClientID{id1, id2})
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/cpsservice/proto/fleetspeak_cpsservice/cpsservice.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.cpsservice;
4 |
5 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/server/cpsservice/proto/fleetspeak_cpsservice";
6 |
7 | message Config {
8 | string project = 1;
9 | string topic = 2; // The cloud pubsub topic to which messages will be posted
10 | // for the service.
11 | }
12 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/db/time.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package db
16 |
17 | import (
18 | "time"
19 |
20 | log "github.com/golang/glog"
21 |
22 | "github.com/google/fleetspeak/fleetspeak/src/server/internal/ftime"
23 | tspb "google.golang.org/protobuf/types/known/timestamppb"
24 | )
25 |
26 | // Now is the clock used by the server. Normally just time.Now, but can be replaced to support testing. It should be used by db.Store implementations to determine the time.
27 | func Now() time.Time {
28 | return ftime.Now()
29 | }
30 |
31 | // NowProto returns a proto representation of Now().
32 | func NowProto() *tspb.Timestamp {
33 | n := tspb.New(Now())
34 | if err := n.CheckValid(); err != nil {
35 | // Really shouldn't happen; the most likely situation is that we
36 | // are in a test using a badly broken Now.
37 | log.Fatalf("Unable to convert Now() to a protocol buffer: %s", err)
38 | }
39 | return n
40 | }
41 |
42 | // ClientRetryTime returns when a client message, being sent to the client
43 | // approximately Now(), will be considered timed out and eligible to be sent
44 | // again. It should be used by MessageStore implementations to determine when a
45 | // message can next be provided by ClientMessagesForProcessing.
46 | func ClientRetryTime() time.Time {
47 | return ftime.ClientRetryTime()
48 | }
49 |
50 | // ServerRetryTime returns when server message, whose processing is about to
51 | // start, will be considered timed out and eligible to be processed again.
52 | // It should be used by MessageStore implementations to determine when a message
53 | // can next be provided to a MessageProcessor.
54 | func ServerRetryTime(retryCount uint32) time.Time {
55 | return ftime.ServerRetryTime(retryCount)
56 | }
57 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/dbtesting/dbtesting.go:
--------------------------------------------------------------------------------
1 | package dbtesting
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/google/fleetspeak/fleetspeak/src/common"
7 | "github.com/google/fleetspeak/fleetspeak/src/server/db"
8 | )
9 |
10 | // DbTestEnv has to be implemented for each datastore where data store tests are expected to run.
11 | type DbTestEnv interface {
12 | // Creates the database testing environment. Called once per database test suite.
13 | Create() error
14 | // Cleans the database testing environment before every test and returns a new Store instance to be used by the test.
15 | Clean() (db.Store, error)
16 | // Destroys the database testing environment after all the tests have run. Called once per database test suite.
17 | Destroy() error
18 | }
19 |
20 | // Predefined client ids to be used in tests.
21 | var clientID, _ = common.BytesToClientID([]byte{0, 0, 0, 0, 0, 0, 0, 1})
22 | var clientID2, _ = common.BytesToClientID([]byte{0, 0, 0, 0, 0, 0, 0, 2})
23 | var clientID3, _ = common.BytesToClientID([]byte{0, 0, 0, 0, 0, 0, 0, 3})
24 |
25 | // RunTestSuite runs a suite of databases tests.
26 | func runTestSuite(t *testing.T, env DbTestEnv, tests map[string]func(*testing.T, db.Store)) {
27 | for n, fn := range tests {
28 | ms, err := env.Clean()
29 | if err != nil {
30 | t.Fatalf("Can't clean the datastore for test '%v': %v", n, err)
31 | }
32 | t.Run(n, func(t *testing.T) {
33 | fn(t, ms)
34 | })
35 | }
36 | }
37 |
38 | // DataStoreTestSuite combines all test suites for datastore testing.
39 | func DataStoreTestSuite(t *testing.T, env DbTestEnv) {
40 | if err := env.Create(); err != nil {
41 | t.Fatalf("Can't create the datastore: %v", err)
42 | }
43 |
44 | messageStoreTestSuite(t, env)
45 | clientStoreTestSuite(t, env)
46 | broadcastStoreTestSuite(t, env)
47 | fileStoreTestSuite(t, env)
48 | integrationTestSuite(t, env)
49 |
50 | if err := env.Destroy(); err != nil {
51 | t.Fatalf("Can't destroy the datastore: %v", err)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/dbtesting/filestore_suite.go:
--------------------------------------------------------------------------------
1 | package dbtesting
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "io"
7 | "testing"
8 |
9 | "github.com/google/fleetspeak/fleetspeak/src/server/db"
10 | "github.com/google/fleetspeak/fleetspeak/src/server/sertesting"
11 | )
12 |
13 | // FileStoreTest tests a FileStore.
14 | func FileStoreTest(t *testing.T, fs db.Store) {
15 | ctx := context.Background()
16 |
17 | fakeTime := sertesting.FakeNow(84)
18 | defer fakeTime.Revert()
19 |
20 | data := []byte("The quick sly fox jumped over the lazy dogs.")
21 |
22 | if err := fs.StoreFile(ctx, "testService", "testFile", bytes.NewReader(data)); err != nil {
23 | t.Errorf("Error from StoreFile(testService, testFile): %v", err)
24 | }
25 |
26 | ts, err := fs.StatFile(ctx, "testService", "testFile")
27 | if err != nil {
28 | t.Errorf("Error from StatFile(testService, testFile): %v", err)
29 | }
30 | if ts != fakeTime.Get() {
31 | t.Errorf("Wrong result of StatfileFile(testService, testFile), want %v got %v:", fakeTime.Get(), ts)
32 | }
33 |
34 | res, ts, err := fs.ReadFile(ctx, "testService", "testFile")
35 | if err != nil {
36 | t.Fatalf("Error from ReadFile(testService, testFile): %v", err)
37 | }
38 | rb, err := io.ReadAll(res)
39 | if err != nil {
40 | t.Errorf("Error reading result of ReadFile(testService, testFile): %v", err)
41 | }
42 | if c, ok := res.(io.Closer); ok {
43 | c.Close()
44 | }
45 | if !bytes.Equal(rb, data) || ts != fakeTime.Get() {
46 | t.Errorf("Wrong result of ReadFile(testService, testFile), want (%v, %v) got (%v, %v):",
47 | fakeTime.Get(), data, ts, rb)
48 | }
49 |
50 | if _, err := fs.StatFile(ctx, "testService", "missingFile"); err == nil || !fs.IsNotFound(err) {
51 | t.Errorf("Wrong error for ReadFile(testService, missingFile), want IsNotFound(err)=true, got %v", err)
52 | }
53 | if _, _, err := fs.ReadFile(ctx, "testService", "missingFile"); err == nil || !fs.IsNotFound(err) {
54 | t.Errorf("Wrong error for ReadFile(testService, missingFile), want IsNotFound(err)=true, got %v", err)
55 | }
56 | }
57 |
58 | func fileStoreTestSuite(t *testing.T, env DbTestEnv) {
59 | t.Run("FileStoreTestSuite", func(t *testing.T) {
60 | runTestSuite(t, env, map[string]func(*testing.T, db.Store){
61 | "FileStoreTest": FileStoreTest,
62 | })
63 | })
64 | }
65 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/dbtesting/integration_suite.go:
--------------------------------------------------------------------------------
1 | package dbtesting
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/google/fleetspeak/fleetspeak/src/inttesting/integrationtest"
7 | "github.com/google/fleetspeak/fleetspeak/src/server/db"
8 | )
9 |
10 | func integrationTest(t *testing.T, ms db.Store) {
11 | integrationtest.FRRIntegrationTest(t, ms, false)
12 | }
13 |
14 | func cloneHandlingTest(t *testing.T, ms db.Store) {
15 | integrationtest.CloneHandlingTest(t, ms)
16 | }
17 |
18 | func integrationTestSuite(t *testing.T, env DbTestEnv) {
19 | t.Run("IntegrationTestSuite", func(t *testing.T) {
20 | runTestSuite(t, env, map[string]func(*testing.T, db.Store){
21 | "IntegrationTest": integrationTest,
22 | "CloneHandlingTest": cloneHandlingTest,
23 | })
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/grpcservice/client/testing/client_test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright 2017 Google Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | #
17 | # Unit test for client.
18 | #
19 | # This script reserves ports and then starts two processes which communicate
20 | # with each other using these ports:
21 | #
22 | # 1) A loopback python script based on the grpcservice client library.
23 | #
24 | # 2) A tester which is, primarily, a fleetspeak server with the grpcservice
25 | # installed.
26 | #
27 | # Then the tester sends a message through the loopback, as if it came from a
28 | # client, and waits for the looped message to come back to the same client.
29 | #
30 | # (Alternatively, this could be done by spawning loopback with tester, but using
31 | # independent processes is more realistic.)
32 |
33 | # Exit on error.
34 | set -e
35 |
36 | readonly LOOPBACK_MODULE='fleetspeak.server_connector.testing.loopback'
37 | readonly TESTER='src/server/grpcservice/client/testing/tester'
38 |
39 | function randomize_tcp_port {
40 | local readonly MINPORT=32760
41 | local readonly MAXPORT=59759
42 | /bin/echo $(( MINPORT + RANDOM%(MAXPORT-MINPORT+1) ))
43 | }
44 |
45 | readonly MESSAGE_PORT=$(randomize_tcp_port)
46 | readonly ADMIN_PORT=$(randomize_tcp_port)
47 |
48 | # Start loopback in the background, kill when finished. We do not care about its
49 | # exit code.
50 | python -m "${LOOPBACK_MODULE}" \
51 | --fleetspeak_message_listen_address="localhost:${MESSAGE_PORT}" \
52 | --fleetspeak_server="localhost:${ADMIN_PORT}" &
53 | readonly PID=${!}
54 | trap "/bin/kill -- $PID ; wait" EXIT SIGINT
55 |
56 | # If anything goes wrong the tester should return a non-zero exit code and as a
57 | # unit test we should preserve this.
58 | "${TESTER}" \
59 | --admin_addr="localhost:${ADMIN_PORT}" \
60 | --message_addr="localhost:${MESSAGE_PORT}"
61 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/grpcservice/proto/fleetspeak_grpcservice/grpcservice.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.grpcservice;
4 |
5 | import "fleetspeak/src/common/proto/fleetspeak/common.proto";
6 |
7 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/server/grpcservice/proto/fleetspeak_grpcservice";
8 |
9 | message Config {
10 | string target = 1; // The address to dial.
11 | bool insecure = 2; // If set, will not secure connection to the target.
12 | string cert_file =
13 | 3; // If set, a pool of trusted certificates will be read from this file
14 | // and used to authenticate the connection to target.
15 | }
16 |
17 | // Processor is the service that a target system must implement to
18 | // receive messages through a GRPCService based service.
19 | service Processor {
20 | // Process accepts message and processes it.
21 | rpc Process(fleetspeak.Message) returns (fleetspeak.EmptyMessage) {}
22 | }
23 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/https/compression.go:
--------------------------------------------------------------------------------
1 | package https
2 |
3 | import (
4 | "compress/zlib"
5 | "fmt"
6 | "net/http"
7 | )
8 |
9 | // CompressionHandler is a http.Handler that transparently decompresses the
10 | // request body if it is compressed and forwards the request to the wrapped
11 | // handler.
12 | type CompressionHandler struct {
13 | Wrapped http.Handler
14 | }
15 |
16 | // ServeHTTP implements http.Handler.ServeHTTP by transparently decompressing
17 | // the request body if it is compressed and forwarding the call to the wrapped
18 | // handler.
19 | func (h *CompressionHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
20 | encoding := req.Header.Get("Content-Encoding")
21 | switch encoding {
22 | case "":
23 | // No compression.
24 | case "deflate":
25 | // "deflate" is the commonly used directive for deflate compressed data in
26 | // zlib format (https://www.rfc-editor.org/rfc/rfc9110#name-deflate-coding).
27 | zr, err := zlib.NewReader(req.Body)
28 | if err != nil {
29 | http.Error(res, fmt.Sprintf("failed to create zlib reader: %v", err), http.StatusBadRequest)
30 | return
31 | }
32 | defer zr.Close()
33 | req.Body = zr
34 | req.Header.Del("Content-Encoding")
35 | default:
36 | http.Error(res, fmt.Sprintf("unsupported content encoding: %s", encoding), http.StatusUnsupportedMediaType)
37 | return
38 | }
39 | h.Wrapped.ServeHTTP(res, req)
40 | }
41 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/https/file_server.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package https
16 |
17 | import (
18 | "fmt"
19 | "net/http"
20 | "net/url"
21 | "strings"
22 | )
23 |
24 | // fileServer wraps a Communicator in order to serve files.
25 | type fileServer struct {
26 | *Communicator
27 | }
28 |
29 | // ServeHTTP implements http.Handler
30 | func (s fileServer) ServeHTTP(res http.ResponseWriter, req *http.Request) {
31 | path := strings.Split(strings.TrimPrefix(req.URL.EscapedPath(), "/"), "/")
32 | if len(path) != 3 || path[0] != "files" {
33 | http.Error(res, fmt.Sprintf("unable to parse files uri: %v", req.URL.EscapedPath()), http.StatusBadRequest)
34 | return
35 | }
36 | service, err := url.PathUnescape(path[1])
37 | if err != nil {
38 | http.Error(res, fmt.Sprintf("unable to parse path component [%v]: %v", path[1], err), http.StatusBadRequest)
39 | return
40 | }
41 | name, err := url.PathUnescape(path[2])
42 | if err != nil {
43 | http.Error(res, fmt.Sprintf("unable to parse path component [%v]: %v", path[2], err), http.StatusBadRequest)
44 | return
45 | }
46 |
47 | ctx := req.Context()
48 | data, modtime, err := s.fs.ReadFile(ctx, service, name)
49 | if err != nil {
50 | if s.fs.IsNotFound(err) {
51 | http.Error(res, "file not found", http.StatusNotFound)
52 | return
53 | }
54 | http.Error(res, fmt.Sprintf("internal error: %v", err), http.StatusInternalServerError)
55 | return
56 | }
57 | http.ServeContent(res, req, name, modtime, data)
58 | data.Close()
59 | }
60 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/internal/ftime/ftime.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package ftime defines "fleetspeak time" as a global variable. This is the
16 | // sense of time used by the fleetspeak server and it can be changed to support
17 | // unit testing.
18 | package ftime
19 |
20 | import "time"
21 |
22 | // Now is the time used by the Fleetspeak system. Variable to support unit testing.
23 | var Now = time.Now
24 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/internal/ftime/retry.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package ftime
16 |
17 | import (
18 | "math"
19 | "math/rand"
20 | "time"
21 | )
22 |
23 | // ClientRetryTime determines how long to wait for an acknowledgement before
24 | // sending a message to a client again. The normal implementation waits 15
25 | // minutes. It is mutable primarily to support testing.
26 | var ClientRetryTime = func() time.Time {
27 | return Now().Add(15 * time.Minute)
28 | }
29 |
30 | // ServerRetryTime determines how long to wait before attempting to process a
31 | // message again on the FS server. The normal implementation provides
32 | // exponential backoff with jitter, with an initial wait of 1-2 min. It is
33 | // mutable primarily to support testing.
34 | var ServerRetryTime = func(retryCount uint32) time.Time {
35 | delay := float64(time.Minute) * math.Pow(1.1, float64(retryCount))
36 | delay *= 1.0 + rand.Float64()
37 |
38 | return Now().Add(time.Duration(delay))
39 | }
40 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/mysql/filestore.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package mysql
16 |
17 | import (
18 | "bytes"
19 | "context"
20 | "database/sql"
21 | "io"
22 | "time"
23 |
24 | "github.com/google/fleetspeak/fleetspeak/src/server/db"
25 | )
26 |
27 | func (d *Datastore) StoreFile(ctx context.Context, service, name string, data io.Reader) error {
28 | b, err := io.ReadAll(data)
29 | if err != nil {
30 | return err
31 | }
32 | return d.runInTx(ctx, false, func(tx *sql.Tx) error {
33 | _, err := tx.ExecContext(ctx, "REPLACE INTO files (service, name, modified_time_nanos, data) VALUES(?, ?, ?, ?)",
34 | service, name, db.Now().UnixNano(), b)
35 | return err
36 | })
37 | }
38 |
39 | func (d *Datastore) StatFile(ctx context.Context, service, name string) (time.Time, error) {
40 | var ts int64
41 |
42 | err := d.runInTx(ctx, true, func(tx *sql.Tx) error {
43 | row := tx.QueryRowContext(ctx, "SELECT modified_time_nanos FROM files WHERE service = ? AND name = ?", service, name)
44 | return row.Scan(&ts)
45 | })
46 |
47 | return time.Unix(0, ts).UTC(), err
48 | }
49 |
50 | func (d *Datastore) ReadFile(ctx context.Context, service, name string) (data db.ReadSeekerCloser, modtime time.Time, err error) {
51 | var b []byte
52 | var ts int64
53 |
54 | err = d.runInTx(ctx, true, func(tx *sql.Tx) error {
55 | row := tx.QueryRowContext(ctx, "SELECT modified_time_nanos, data FROM files WHERE service = ? AND name = ?", service, name)
56 | if err := row.Scan(&ts, &b); err != nil {
57 | b = nil
58 | return err
59 | }
60 | return nil
61 | })
62 |
63 | if err != nil {
64 | return nil, time.Time{}, err
65 | }
66 | if b == nil {
67 | b = []byte{}
68 | }
69 | return db.NOOPCloser{ReadSeeker: bytes.NewReader(b)}, time.Unix(0, ts).UTC(), nil
70 | }
71 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/notifications/notifications.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package notifications defines the plugin interface for components which allow
16 | // the fleetspeak servers within an installation to notify each other about
17 | // interesting events.
18 | package notifications
19 |
20 | import (
21 | "context"
22 |
23 | "github.com/google/fleetspeak/fleetspeak/src/common"
24 | )
25 |
26 | type Listener interface {
27 | // Start causes the Listener to begin listening for notifications. Once
28 | // started, should write to ids every time it is notified that there may be
29 | // new messages for a client.
30 | Start() (<-chan common.ClientID, error)
31 |
32 | // Stop causes the Listener to stop listening for notifications and close the
33 | // ids channel.
34 | Stop()
35 |
36 | // Address returns the address of this listener. These addresses must be
37 | // suitable to pass as a target to any Notifier compatible with this Listener.
38 | // Will only be called after Start().
39 | Address() string
40 | }
41 |
42 | type Notifier interface {
43 | // NewMessageForClient indicates that one or more messages have been written
44 | // and notifies the provided target of this.
45 | NewMessageForClient(ctx context.Context, target string, id common.ClientID) error
46 | }
47 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/proto/fleetspeak_server/broadcasts.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.server;
4 |
5 | import "fleetspeak/src/common/proto/fleetspeak/common.proto";
6 | import "google/protobuf/any.proto";
7 | import "google/protobuf/timestamp.proto";
8 |
9 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/server/proto/fleetspeak_server";
10 |
11 | // A Broadcast is a template to build messages to send to a number of machines.
12 | message Broadcast {
13 | bytes broadcast_id = 1;
14 |
15 | // The source of the broadcast, it should only be a server side service. The
16 | // destinations for the resulting broadcast messages will be different clients
17 | // with the same service name.
18 | fleetspeak.Address source = 2;
19 |
20 | string message_type = 3;
21 |
22 | // A client will only be sent this broadcast if it has been marked with all of
23 | // the required labels.
24 | repeated fleetspeak.Label required_labels = 4;
25 |
26 | // A broadcast will stop being sent at this time.
27 | google.protobuf.Timestamp expiration_time = 5;
28 |
29 | google.protobuf.Any data = 6;
30 | }
31 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/proto/fleetspeak_server/resource.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.server;
4 |
5 | import "google/protobuf/timestamp.proto";
6 |
7 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/server/proto/fleetspeak_server";
8 |
9 | // Represents client resource-usage data in the data-store.
10 | // Next id: 15
11 | message ClientResourceUsageRecord {
12 | // Name of the client service that resource usage is charged/attributed to
13 | // e.g 'system' for the system Fleetspeak service, or the name of a daemon
14 | // service as specified in its config.
15 | string scope = 1;
16 |
17 | int64 pid = 2;
18 | google.protobuf.Timestamp process_start_time = 3;
19 |
20 | // When the resource-usage metrics were measured on the client.
21 | google.protobuf.Timestamp client_timestamp = 4;
22 |
23 | // When the resource usage record was written to the data-store.
24 | google.protobuf.Timestamp server_timestamp = 5;
25 |
26 | // If true, indicates that the process has terminated, and that this is
27 | // the final resource-usage record for that process.
28 | bool process_terminated = 12;
29 |
30 | // CPU-usage is in millis per second.
31 | float mean_user_cpu_rate = 6;
32 | float max_user_cpu_rate = 7;
33 | float mean_system_cpu_rate = 8;
34 | float max_system_cpu_rate = 9;
35 |
36 | int32 mean_resident_memory_mib = 10;
37 | int32 max_resident_memory_mib = 11;
38 |
39 | int32 mean_num_fds = 13;
40 | int32 max_num_fds = 14;
41 | }
42 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/proto/fleetspeak_server/server.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.server;
4 |
5 | import "fleetspeak/src/server/proto/fleetspeak_server/services.proto";
6 | import "google/protobuf/duration.proto";
7 |
8 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/server/proto/fleetspeak_server";
9 |
10 | // Describes a server's configuration. If unset, all values default to values
11 | // reasonable for a unit test or small installation. Larger installations may
12 | // need to tune these.
13 | message ServerConfig {
14 | // The collection of services that this server should include.
15 | repeated ServiceConfig services = 1;
16 |
17 | // The approximate time to wait between checking for new broadcasts. If unset,
18 | // a default of 1 minute is used.
19 | google.protobuf.Duration broadcast_poll_time = 2;
20 | }
21 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/proto/fleetspeak_server/services.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package fleetspeak.server;
4 |
5 | import "google/protobuf/any.proto";
6 |
7 | option go_package = "github.com/google/fleetspeak/fleetspeak/src/server/proto/fleetspeak_server";
8 |
9 | // A ServiceConfig describes how the server should configure a 'service', which
10 | // is a module that sends and processes messages.
11 | message ServiceConfig {
12 | // The name that the service will be known as. Primary use is to address
13 | // messages to the service. The service names 'server' and 'client' are
14 | // reserved.
15 | string name = 1;
16 |
17 | // The name of the factory which will be used to generate the service.
18 | string factory = 2;
19 |
20 | // The maximum number of simultaneous calls to the service's ProcessMessage
21 | // method. If unset, defaults to 100.
22 | uint32 max_parallelism = 3;
23 |
24 | // Additional configuration information for the factory to use when setting up
25 | // the service. The allowed type depends upon the factory.
26 | google.protobuf.Any config = 4;
27 | }
28 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/sertesting/cache.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package sertesting
16 |
17 | import (
18 | "time"
19 |
20 | "github.com/google/fleetspeak/fleetspeak/src/server/internal/cache"
21 | )
22 |
23 | // SetClientCacheMaxAge adjusts the maximum age that cached client data is
24 | // considered valid for. This can be used to make tests run faster.
25 | func SetClientCacheMaxAge(d time.Duration) func() {
26 | o := cache.MaxAge
27 | cache.MaxAge = d
28 | return func() {
29 | cache.MaxAge = o
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/sertesting/context.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package sertesting
16 |
17 | import (
18 | "context"
19 |
20 | "github.com/google/fleetspeak/fleetspeak/src/common"
21 | "github.com/google/fleetspeak/fleetspeak/src/server/db"
22 |
23 | fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
24 | )
25 |
26 | // A FakeContext is a fake service.Context, suitable for unit testing services.
27 | type FakeContext struct {
28 | SentMessages chan *fspb.Message
29 | ClientData map[common.ClientID]*db.ClientData
30 | }
31 |
32 | func (c *FakeContext) Send(ctx context.Context, m *fspb.Message) error {
33 | select {
34 | case c.SentMessages <- m:
35 | return nil
36 | case <-ctx.Done():
37 | return ctx.Err()
38 | }
39 | }
40 |
41 | func (c *FakeContext) GetClientData(_ context.Context, id common.ClientID) (*db.ClientData, error) {
42 | return c.ClientData[id], nil
43 | }
44 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/sertesting/retry.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package sertesting
16 |
17 | import (
18 | "time"
19 |
20 | "github.com/google/fleetspeak/fleetspeak/src/server/internal/ftime"
21 | )
22 |
23 | // SetClientRetryTime changes db.ClientRetryTime method used by datastores to
24 | // decide when to retry requests to clients. It returns a closure which returns
25 | // the system to the previous state.
26 | //
27 | // This function and the returned closure are not thread safe. In particular, they should
28 | // be called at the start and end of tests when no Fleetspeak component is started.
29 | func SetClientRetryTime(f func() time.Time) func() {
30 | op := ftime.ClientRetryTime
31 | ftime.ClientRetryTime = f
32 | return func() {
33 | ftime.ClientRetryTime = op
34 | }
35 | }
36 |
37 | // SetServerRetryTime changes the db.ServerRetryTime used by the Fleetspeak
38 | // server to decide when to retry requests to clients. It returns a closure
39 | // which returns the system to the previous state.
40 | //
41 | // This function and the returned closure are not thread safe. In particular, they should
42 | // be called at the start and end of tests when no Fleetspeak component is started.
43 | func SetServerRetryTime(f func(uint32) time.Time) func() {
44 | op := ftime.ServerRetryTime
45 | ftime.ServerRetryTime = f
46 | return func() {
47 | ftime.ServerRetryTime = op
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/sertesting/time.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Package sertesting contains utilities useful for testing the fleetspeak server
16 | // and server components.
17 | package sertesting
18 |
19 | import (
20 | "sync/atomic"
21 | "time"
22 |
23 | "github.com/google/fleetspeak/fleetspeak/src/server/internal/ftime"
24 | )
25 |
26 | // FakeTime represents a fake time which can control the time seen by the fleetspeak
27 | // system during unit tests.
28 | type FakeTime struct {
29 | t int64
30 | orig func() time.Time
31 | }
32 |
33 | // Get returns the current fake time.
34 | func (t *FakeTime) Get() time.Time {
35 | return time.Unix(atomic.LoadInt64(&t.t), 0).UTC()
36 | }
37 |
38 | // SetSeconds sets the current fake time to s seconds since epoch.
39 | func (t *FakeTime) SetSeconds(s int64) {
40 | atomic.StoreInt64(&t.t, s)
41 | }
42 |
43 | // AddSeconds adds s seconds to the fake time.
44 | func (t *FakeTime) AddSeconds(s int64) {
45 | atomic.AddInt64(&t.t, s)
46 | }
47 |
48 | // Revert returns the time seen by the fleetspeak system to what it was
49 | // previously.
50 | func (t *FakeTime) Revert() {
51 | ftime.Now = t.orig
52 | }
53 |
54 | // FakeNow changes the implementation of Now used by the fleetspeak system. It
55 | // returns a FakeTime which controls the time that the system sees until Revert
56 | // is called.
57 | //
58 | // Note that this function, and FakeTime.Revert are not thread safe. In
59 | // particular it they should be called at the start and end of tests when no Fleetspeak
60 | // component is started.
61 | func FakeNow(start int64) *FakeTime {
62 | r := FakeTime{
63 | t: start,
64 | orig: ftime.Now,
65 | }
66 | ftime.Now = r.Get
67 | return &r
68 | }
69 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/service/service_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package service
16 |
17 | import (
18 | "errors"
19 | "testing"
20 | )
21 |
22 | type netErr struct {
23 | msg string
24 | timeout bool
25 | }
26 |
27 | func (e netErr) Error() string {
28 | return e.msg
29 | }
30 |
31 | func (e netErr) Temporary() bool {
32 | return e.timeout
33 | }
34 |
35 | func (e netErr) Timeout() bool {
36 | return e.timeout
37 | }
38 |
39 | func TestIsTemporary(t *testing.T) {
40 | for _, tc := range []struct {
41 | e error
42 | want bool
43 | }{
44 | {
45 | e: errors.New("a permanent error"),
46 | want: false,
47 | },
48 | {
49 | e: TemporaryError{errors.New("a temporary error")},
50 | want: true,
51 | },
52 | {
53 | e: &TemporaryError{errors.New("a referenced temporary error")},
54 | want: true,
55 | },
56 | {
57 | e: netErr{msg: "A generic net.Error"},
58 | want: false,
59 | },
60 | {
61 | e: netErr{msg: "A timeout net.Error", timeout: true},
62 | want: true,
63 | },
64 | } {
65 | got := IsTemporary(tc.e)
66 | if got != tc.want {
67 | t.Errorf("IsTemporary(%T)=%v, but want %v", tc.e, got, tc.want)
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/sqlite/filestore.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package sqlite
16 |
17 | import (
18 | "bytes"
19 | "context"
20 | "database/sql"
21 | "io"
22 | "time"
23 |
24 | "github.com/google/fleetspeak/fleetspeak/src/server/db"
25 | )
26 |
27 | func (d *Datastore) StoreFile(ctx context.Context, service, name string, data io.Reader) error {
28 | b, err := io.ReadAll(data)
29 | if err != nil {
30 | return err
31 | }
32 | d.l.Lock()
33 | defer d.l.Unlock()
34 | return d.runInTx(func(tx *sql.Tx) error {
35 | _, err := tx.ExecContext(ctx, "INSERT OR REPLACE INTO files (service, name, modified_time_nanos, data) VALUES(?, ?, ?, ?)",
36 | service, name, db.Now().UnixNano(), b)
37 | return err
38 | })
39 | }
40 |
41 | func (d *Datastore) StatFile(ctx context.Context, service, name string) (time.Time, error) {
42 | d.l.Lock()
43 | defer d.l.Unlock()
44 |
45 | var ts int64
46 |
47 | err := d.runInTx(func(tx *sql.Tx) error {
48 | row := tx.QueryRowContext(ctx, "SELECT modified_time_nanos FROM files WHERE service = ? AND name = ?", service, name)
49 | return row.Scan(&ts)
50 | })
51 |
52 | return time.Unix(0, ts).UTC(), err
53 | }
54 |
55 | func (d *Datastore) ReadFile(ctx context.Context, service, name string) (data db.ReadSeekerCloser, modtime time.Time, err error) {
56 | d.l.Lock()
57 | defer d.l.Unlock()
58 |
59 | var b []byte
60 | var ts int64
61 |
62 | err = d.runInTx(func(tx *sql.Tx) error {
63 | row := tx.QueryRowContext(ctx, "SELECT modified_time_nanos, data FROM files WHERE service = ? AND name = ?", service, name)
64 | if err := row.Scan(&ts, &b); err != nil {
65 | b = nil
66 | return err
67 | }
68 | return nil
69 | })
70 |
71 | if err != nil {
72 | return nil, time.Time{}, err
73 | }
74 | if b == nil {
75 | b = []byte{}
76 | }
77 | return db.NOOPCloser{ReadSeeker: bytes.NewReader(b)}, time.Unix(0, ts).UTC(), nil
78 | }
79 |
--------------------------------------------------------------------------------
/fleetspeak/src/server/sqlite/sqlite_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package sqlite
16 |
17 | import (
18 | "fmt"
19 | "path"
20 | "testing"
21 |
22 | "github.com/google/fleetspeak/fleetspeak/src/comtesting"
23 |
24 | log "github.com/golang/glog"
25 |
26 | "github.com/google/fleetspeak/fleetspeak/src/server/db"
27 | "github.com/google/fleetspeak/fleetspeak/src/server/dbtesting"
28 | )
29 |
30 | type sqliteTestEnv struct {
31 | tempDirCleanup func()
32 | counter int
33 | }
34 |
35 | func (e *sqliteTestEnv) Create() error {
36 | return nil
37 | }
38 |
39 | func (e *sqliteTestEnv) Clean() (db.Store, error) {
40 | dir, fn := comtesting.GetTempDir("sqlite_test")
41 | e.tempDirCleanup = fn
42 |
43 | p := path.Join(dir, fmt.Sprintf("%d.sqlite", e.counter))
44 | e.counter++
45 |
46 | log.Infof("Using database: %v", p)
47 | s, err := MakeDatastore(p)
48 | if err != nil {
49 | return nil, err
50 | }
51 | return s, nil
52 | }
53 |
54 | func (e *sqliteTestEnv) Destroy() error {
55 | e.tempDirCleanup()
56 | return nil
57 | }
58 |
59 | func TestSqliteStore(t *testing.T) {
60 | dbtesting.DataStoreTestSuite(t, &sqliteTestEnv{})
61 | }
62 |
--------------------------------------------------------------------------------
/fleetspeak/src/windows/hashpipe/hashpipe.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package hashpipe
16 |
--------------------------------------------------------------------------------
/fleetspeak/src/windows/hashpipe/hashpipe_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package hashpipe
16 |
17 | import (
18 | "testing"
19 | )
20 |
21 | func TestNoop(t *testing.T) {}
22 |
--------------------------------------------------------------------------------
/fleetspeak/src/windows/hashpipe/hashpipe_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build windows
16 |
17 | // Package hashpipe implements a name randomization mechanism over Windows
18 | // named pipes.
19 | package hashpipe
20 |
21 | import (
22 | "crypto/rand"
23 | "encoding/base64"
24 | "fmt"
25 | "net"
26 |
27 | "github.com/Microsoft/go-winio"
28 | )
29 |
30 | // ListenPipe refines winio.ListenPipe by providing a crypto-secure random name
31 | // for the pipe and returning the name alongside the normal net.Listener.
32 | func ListenPipe(c *winio.PipeConfig) (l net.Listener, path string, err error) {
33 | if path, err = randomizePath(); err != nil {
34 | return
35 | }
36 |
37 | l, err = winio.ListenPipe(path, c)
38 | return
39 | }
40 |
41 | func randomizePath() (string, error) {
42 | // 96 bytes of information gives us 128 base-64 characters. Windows named
43 | // pipes support paths of up to 256 characters. See:
44 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365783(v=vs.85).aspx
45 | randBuf := make([]byte, 96)
46 |
47 | if n, err := rand.Read(randBuf); err != nil {
48 | return "", fmt.Errorf("error in rand.Read (%d bytes read): %v", n, err)
49 | }
50 |
51 | randB64String := base64.URLEncoding.EncodeToString(randBuf)
52 |
53 | pipePath := `\\.\pipe\` + randB64String
54 | return pipePath, nil
55 | }
56 |
--------------------------------------------------------------------------------
/fleetspeak/src/windows/regutil/regutil.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package regutil
16 |
--------------------------------------------------------------------------------
/fleetspeak/src/windows/regutil/regutil_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | //go:build !windows
16 |
17 | package regutil
18 |
19 | import (
20 | "testing"
21 | )
22 |
23 | func TestNoop(t *testing.T) {}
24 |
--------------------------------------------------------------------------------
/fleetspeak/src/windows/wnixsocket/wnixsocket.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package wnixsocket
16 |
--------------------------------------------------------------------------------
/fleetspeak/src/windows/wnixsocket/wnixsocket_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package wnixsocket
16 |
17 | import (
18 | "testing"
19 | )
20 |
21 | func TestNoop(t *testing.T) {}
22 |
--------------------------------------------------------------------------------
/fleetspeak/test-package.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright 2019 Google Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | set -ex
17 |
18 | /bin/echo 'Installing newly built server package.'
19 | apt install -y $1
20 |
21 | if [[ ! -z "$MYSQL_TEST_USER" ]]
22 | then
23 | sed -i "s/mysql_data_source_name: .*/mysql_data_source_name: \"$MYSQL_TEST_USER:$MYSQL_TEST_PASS@tcp($MYSQL_TEST_ADDR)\/$MYSQL_TEST_E2E_DB\"/g" /etc/fleetspeak-server/configurator.config
24 | fi
25 |
26 | sudo -u fleetspeak /usr/bin/fleetspeak-config --config=/etc/fleetspeak-server/configurator.config
27 |
28 | /bin/echo 'Checking that the installation was successful'
29 | ls -l /etc/fleetspeak-server
30 | find /etc/systemd/ -name 'fleetspeak*'
31 |
32 | # At this point the service is down, since right after the installation it was
33 | # started without a configuration.
34 | # Reset a list of failed services to ensure the restart below works fine.
35 | systemctl reset-failed
36 |
37 | # Restart the service.
38 | systemctl restart fleetspeak-server
39 |
40 | # Check that it's now up and running.
41 | systemctl is-active fleetspeak-server
42 |
43 | # Now copy the linux client configuration to the expected location.
44 | mkdir -p /etc/fleetspeak-client
45 | cp /etc/fleetspeak-server/linux.client.configuration /etc/fleetspeak-client/client.config
46 |
47 | # Install the client package.
48 | apt install -y $2
49 |
50 | # Check that the client is up and running.
51 | systemctl is-active fleetspeak-client
52 |
53 | journalctl -u fleetspeak-server
54 | journalctl -u fleetspeak-client
55 | systemctl -l status fleetspeak-server
56 | systemctl -l status fleetspeak-client
57 |
58 | # Check that fleetspeak_admin functions and returns info about a single client we have.
59 | fleetspeak-admin -admin_addr localhost:9000 listclients | grep "[a-z0-9]\{16\} .*client:linux"
60 |
--------------------------------------------------------------------------------
/fleetspeak/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright 2017 Google Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 |
17 | # Get absolute path to symlink's directory
18 | set +e # Do not exit if readlink errors out
19 | SCRIPT_DIR="$(/usr/bin/dirname "$(readlink -e "${ARGV0}" 2>/dev/null)")"
20 | # Exit on error.
21 | set -e
22 | if [[ -z "${SCRIPT_DIR}" || "${SCRIPT_DIR}" == '.' ]]; then
23 | SCRIPT_DIR="$(/usr/bin/dirname "${BASH_SOURCE[0]}")"
24 | if [[ -z "${SCRIPT_DIR}" ]]; then
25 | /bin/echo 'Failed to resolve script directory.'
26 | exit 1
27 | fi
28 | fi
29 | # Go to this script's directory.
30 | cd "${SCRIPT_DIR}"
31 |
32 | readonly TEST_SHS='src/server/grpcservice/client/testing/client_test.sh'
33 |
34 | function test_single_sh {
35 | local readonly SH=${1}
36 |
37 | OUT=$("${SH}" 2>&1)
38 |
39 | if [ "$?" -ne 0 ]; then
40 | /bin/echo "FAIL ${SH}"
41 | /bin/echo "${OUT}"
42 | return 1
43 | fi
44 |
45 | /bin/echo "PASS ${SH}"
46 | }
47 |
48 | function pretty_echo {
49 | /bin/echo '---'
50 | /bin/echo "${@}"
51 | /bin/echo '---'
52 | }
53 |
54 | RC=0
55 |
56 | pretty_echo 'Building prerequisites for Go tests.'
57 | go build -o ./src/e2etesting/frr_master_server_main/frr_master_server_main{,.go}
58 | go build -o ./src/e2etesting/balancer/balancer{,.go}
59 | go build -o ./src/client/daemonservice/testclient/testclient{,.go}
60 | go build -o ./src/client/socketservice/testclient/testclient{,.go}
61 | go build -o ./src/server/grpcservice/client/testing/tester{,.go}
62 | cd ..
63 | # Required for src/e2etesting/localtesting.
64 | go build -o ./cmd/fleetspeak_config/fleetspeak_config{,.go}
65 | go build -o ./cmd/fleetspeak_client/fleetspeak_client{,.go}
66 | go build -o ./cmd/fleetspeak_server/fleetspeak_server{,.go}
67 | cd -
68 |
69 | pretty_echo 'Executing Go tests.'
70 | go test -race --timeout 2.5m ./... || RC=1
71 |
72 | pretty_echo 'Executing Python tests.'
73 | pytest -v ../fleetspeak_python || RC=2
74 |
75 | pretty_echo 'Executing Bash tests.'
76 | for s in ${TEST_SHS}; do
77 | test_single_sh "${s}" || RC=3
78 | done
79 |
80 | exit "${RC}"
81 |
--------------------------------------------------------------------------------
/fleetspeak_python/fleetspeak/client_connector/testing/testclient_launcher.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2018 Google Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | """Script that launches testclient.Loopback in another process."""
17 |
18 | import subprocess
19 |
20 | from absl import app
21 |
22 |
23 | def main(argv=None):
24 | del argv
25 | p = subprocess.Popen(
26 | [
27 | "python",
28 | "-m",
29 | "fleetspeak.client_connector.testing.testclient",
30 | "--",
31 | "--mode=loopback",
32 | ],
33 | # Make sure file descriptors passed from the parent Fleetspeak process are
34 | # not closed. This is critical for inter-process communication between
35 | # the Fleetspeak client and the test client.
36 | close_fds=False,
37 | )
38 | p.communicate()
39 | p.wait()
40 |
41 |
42 | if __name__ == "__main__":
43 | app.run(main)
44 |
--------------------------------------------------------------------------------
/fleetspeak_python/fleetspeak/server_connector/testing/loopback.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 Google Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """A simple GRPCService based loopback.
16 |
17 | This script uses the GRPCService client library to receive messages from
18 | a fleetspeak server. They are returned to the sending address, again
19 | using the GRPCService client library.
20 | """
21 |
22 | import logging
23 | import threading
24 | import time
25 |
26 | from absl import app
27 | from absl import flags
28 | from fleetspeak.server_connector import connector
29 |
30 | FLAGS = flags.FLAGS
31 |
32 |
33 | def main(argv=None):
34 | del argv # Unused.
35 |
36 | service_client = connector.InsecureGRPCServiceClient("TestService")
37 | seen = set()
38 | seen_lock = threading.Lock()
39 |
40 | def loop(message, context):
41 | """loop a message back to fleetspeak."""
42 | del context # Unused
43 |
44 | logging.info("Received message.")
45 | with seen_lock:
46 | if message.message_id in seen:
47 | logging.warning("Ignoring duplicate.")
48 | return
49 | seen.add(message.message_id)
50 |
51 | message.ClearField("source_message_id")
52 | message.ClearField("message_id")
53 | message.destination.service_name = message.source.service_name
54 | message.destination.client_id = message.source.client_id
55 |
56 | service_client.outgoing.InsertMessage(message)
57 | logging.info("Sent message.")
58 |
59 | service_client.Listen(loop)
60 | while True:
61 | time.sleep(600)
62 |
63 |
64 | if __name__ == "__main__":
65 | app.run(main)
66 |
--------------------------------------------------------------------------------
/frr_python/frr_client.py:
--------------------------------------------------------------------------------
1 | """FRR Fleetspeak client
2 |
3 | Receives TrafficRequestData messages from server service and responses with
4 | TrafficResponseData
5 | """
6 |
7 | from absl import app
8 | from fleetspeak.client_connector.connector import FleetspeakConnection
9 | from fleetspeak.src.common.proto.fleetspeak.common_pb2 import Message
10 | from fleetspeak.src.inttesting.frr.proto.fleetspeak_frr.frr_pb2 import TrafficRequestData
11 | from fleetspeak.src.inttesting.frr.proto.fleetspeak_frr.frr_pb2 import TrafficResponseData
12 |
13 |
14 | def main(argv):
15 | del argv # Unused.
16 |
17 | connection = FleetspeakConnection(version="0.0.1")
18 | while True:
19 | request, _ = connection.Recv()
20 | if request.message_type != "TrafficRequest":
21 | continue
22 |
23 | request_data = TrafficRequestData()
24 | request.data.Unpack(request_data)
25 |
26 | response_data = TrafficResponseData(
27 | master_id=request_data.master_id,
28 | request_id=request_data.request_id,
29 | response_index=0,
30 | data=b"client response",
31 | fin=True,
32 | )
33 |
34 | response = Message()
35 | response.destination.service_name = request.source.service_name
36 | response.data.Pack(response_data)
37 | response.message_type = "TrafficResponse"
38 |
39 | connection.Send(response)
40 |
41 |
42 | if __name__ == "__main__":
43 | app.run(main)
44 |
--------------------------------------------------------------------------------
/frr_python/frr_server.py:
--------------------------------------------------------------------------------
1 | """FRR Fleetspeak server
2 |
3 | Receives messages from a client, prints them and forwards them to master server
4 | """
5 |
6 | import logging
7 | import time
8 | from absl import app
9 | from absl import flags
10 | from fleetspeak.server_connector.connector import InsecureGRPCServiceClient
11 | from fleetspeak.src.inttesting.frr.proto.fleetspeak_frr.frr_pb2 import MessageInfo
12 | from fleetspeak.src.inttesting.frr.proto.fleetspeak_frr.frr_pb2 import TrafficResponseData
13 | from fleetspeak.src.inttesting.frr.proto.fleetspeak_frr.frr_pb2_grpc import MasterStub
14 | import grpc
15 |
16 |
17 | FLAGS = flags.FLAGS
18 |
19 | flags.DEFINE_string(
20 | name="master_server_address",
21 | default="localhost:6059",
22 | help="Address of master server to forward clients' messages",
23 | )
24 |
25 |
26 | class Listener:
27 | """Connects to master server and processes messages from clients"""
28 |
29 | def __init__(self):
30 | channel = grpc.insecure_channel(FLAGS.master_server_address)
31 | self.stub = MasterStub(channel)
32 |
33 | def __call__(self, message, context):
34 | del context # Unused
35 |
36 | if message.message_type != "TrafficResponse":
37 | logging.info("Unknown message type: %s", message.message_type)
38 | return
39 |
40 | response_data = TrafficResponseData()
41 | message.data.Unpack(response_data)
42 | logging.info(
43 | "RESPONSE - master_id: %d, "
44 | "request_id: %d, "
45 | "response_index: %d, "
46 | "text: %s",
47 | response_data.master_id,
48 | response_data.request_id,
49 | response_data.response_index,
50 | response_data.data,
51 | )
52 |
53 | self.stub.RecordTrafficResponse(
54 | MessageInfo(client_id=message.source.client_id, data=response_data)
55 | )
56 |
57 |
58 | def main(argv=None):
59 | del argv # Unused.
60 |
61 | service_client = InsecureGRPCServiceClient("FRR")
62 | service_client.Listen(Listener())
63 |
64 | while True:
65 | time.sleep(1)
66 |
67 |
68 | if __name__ == "__main__":
69 | app.run(main)
70 |
--------------------------------------------------------------------------------
/frr_python/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 | import sys
4 |
5 | from setuptools import setup
6 | from setuptools.command.develop import develop
7 |
8 | GRPCIO_TOOLS = "grpcio-tools==1.69.0"
9 | THIS_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
10 | os.chdir(THIS_DIRECTORY)
11 |
12 |
13 | def compile_protos():
14 | """Compiles all proto files."""
15 | p = subprocess.Popen(
16 | [sys.executable, "-m", "grpc_tools.protoc", "--help"],
17 | stdout=subprocess.PIPE,
18 | stderr=subprocess.PIPE,
19 | )
20 | p.communicate()
21 | if p.returncode != 0:
22 | subprocess.check_call(
23 | [sys.executable, "-m", "pip", "install", GRPCIO_TOOLS]
24 | )
25 |
26 | proto_files = []
27 | for dir_path, _, filenames in os.walk(os.path.join(THIS_DIRECTORY, "..")):
28 | for filename in filenames:
29 | if filename.endswith(".proto"):
30 | proto_files.append(os.path.join(dir_path, filename))
31 | if not proto_files:
32 | return
33 |
34 | root_dir = os.path.join(THIS_DIRECTORY, "..")
35 | protoc_command = [
36 | "python",
37 | "-m",
38 | "grpc_tools.protoc",
39 | "--python_out",
40 | THIS_DIRECTORY,
41 | "--grpc_python_out",
42 | THIS_DIRECTORY,
43 | "--proto_path",
44 | root_dir,
45 | ]
46 | protoc_command.extend(proto_files)
47 | subprocess.check_call(protoc_command, cwd=root_dir)
48 |
49 |
50 | class Develop(develop):
51 |
52 | def run(self):
53 | compile_protos()
54 | develop.run(self)
55 |
56 |
57 | setup(
58 | name="frr_python",
59 | description="Frr server and client services",
60 | url="https://github.com/google/fleetspeak/tree/master/frr_python",
61 | maintainer="GRR Development Team",
62 | maintainer_email="grr-dev@googlegroups.com",
63 | license="Apache License, Version 2.0",
64 | py_modules=["frr_client", "frr_server"],
65 | install_requires=["absl-py>=0.8.0", "fleetspeak>=0.1.7"],
66 | cmdclass={
67 | "develop": Develop,
68 | },
69 | )
70 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/fleetspeak-client/communicator.txt:
--------------------------------------------------------------------------------
1 | prefer_http2: true
2 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/fleetspeak-client/config.textproto:
--------------------------------------------------------------------------------
1 | server: "fleetspeak-frontend:10000"
2 | client_certificate_header: "client-certificate"
3 | trusted_certs:"FRONTEND_CERTIFICATE"
4 | client_label: ""
5 | filesystem_handler: {
6 | configuration_directory:"/config/fleetspeak-client"
7 | state_file:"/fleetspeak-client.state"
8 | }
9 | streaming:true
10 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/fleetspeak-client/textservices/hello.service:
--------------------------------------------------------------------------------
1 | name: "hello"
2 | factory: "Daemon"
3 | config: {
4 | [type.googleapis.com/fleetspeak.daemonservice.Config]: {
5 | argv: "/venv/FSENV/bin/python"
6 | argv: "/config/hello.py"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/fleetspeak-server/components.textproto:
--------------------------------------------------------------------------------
1 | mysql_data_source_name:"fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
2 | https_config: {
3 | listen_address: "0.0.0.0:9090"
4 | certificates:"FRONTEND_CERTIFICATE"
5 | key:"FRONTEND_KEY"
6 | frontend_config: {
7 | cleartext_header_checksum_config: {
8 | client_certificate_header: "client-certificate"
9 | client_certificate_checksum_header: "x-client-cert-hash"
10 | }
11 | }
12 | }
13 | admin_config: {
14 | listen_address: "0.0.0.0:9091"
15 | }
16 | health_check_config: {
17 | listen_address: "0.0.0.0:8080"
18 | }
19 | notification_use_http_notifier:false
20 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/fleetspeak-server/services.textproto:
--------------------------------------------------------------------------------
1 | services {
2 | name: "greeter"
3 | factory: "GRPC"
4 | config: {
5 | [type.googleapis.com/fleetspeak.grpcservice.Config] {
6 | target: "greeter:1337"
7 | insecure: true
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/fleetspeak.textproto:
--------------------------------------------------------------------------------
1 | configuration_name: "Example"
2 |
3 | components_config {
4 |
5 | mysql_data_source_name: "fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
6 |
7 | https_config {
8 | listen_address: "fleetspeak-server:9090"
9 | }
10 |
11 | admin_config {
12 | listen_address: "fleetspeak-server:9091"
13 | }
14 | }
15 |
16 | public_host_port: "fleetspeak-server:9090"
17 |
18 | trusted_cert_file: "/config/fleetspeak-server/ca.pem"
19 | trusted_cert_key_file: "/config/fleetspeak-server/ca-key.pem"
20 |
21 | server_cert_file: "/config/fleetspeak-server/server.pem"
22 | server_cert_key_file: "/config/fleetspeak-server/server-key.pem"
23 |
24 | server_component_configuration_file: "/config/fleetspeak-server/components.textproto"
25 | linux_client_configuration_file: "/config/fleetspeak-client/config.textproto"
26 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/hello.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from absl import app
16 | from fleetspeak.client_connector.connector import FleetspeakConnection
17 | from fleetspeak.src.common.proto.fleetspeak.common_pb2 import Message
18 | from google.protobuf.wrappers_pb2 import StringValue
19 |
20 |
21 | def main(argv):
22 | del argv # Unused.
23 |
24 | conn = FleetspeakConnection(version="0.0.1")
25 | while True:
26 | request, _ = conn.Recv()
27 |
28 | data = StringValue()
29 | request.data.Unpack(data)
30 |
31 | data.value = f"Hello {data.value}!"
32 |
33 | response = Message()
34 | response.destination.service_name = request.source.service_name
35 | response.data.Pack(data)
36 |
37 | conn.Send(response)
38 |
39 |
40 | if __name__ == "__main__":
41 | app.run(main)
42 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/config/hello.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | /venv/FSENV/bin/python /config/hello.py
3 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-header-mode/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | mysql-server:
4 | image: mysql:8.2
5 | restart: always
6 | hostname: mysql-server
7 | environment:
8 | MYSQL_DATABASE: 'fleetspeak'
9 | MYSQL_USER: 'fleetspeak-user'
10 | MYSQL_PASSWORD: 'fleetspeak-password'
11 | MYSQL_ROOT_PASSWORD: 'password'
12 | ports:
13 | - '3306:3306'
14 | expose:
15 | - '3306'
16 | healthcheck:
17 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
18 | timeout: 5s
19 | retries: 10
20 |
21 | front-envoy:
22 | build:
23 | context: .
24 | dockerfile: ../shared/envoy/Dockerfile
25 | args:
26 | ENVOY_CONFIG: ./envoy-https-http.yaml
27 | hostname: fleetspeak-frontend
28 | ports:
29 | - "10000:10000"
30 |
31 | fleetspeak-server:
32 | build:
33 | context: .
34 | dockerfile: ../shared/fleetspeak-server/Dockerfile
35 | hostname: fleetspeak-server
36 | depends_on:
37 | mysql-server:
38 | condition: service_healthy
39 | entrypoint: ["/app/bin/server", "-components_config", "/config/fleetspeak-server/components.textproto", "-services_config", "/config/fleetspeak-server/services.textproto", "-alsologtostderr"]
40 | volumes:
41 | - "./config:/config"
42 | ports:
43 | - '9090:9090'
44 | - '9091:9091'
45 | - '8080:8080'
46 | expose:
47 | - '9090'
48 | - '9091'
49 | - '8080'
50 | healthcheck:
51 | test: ["CMD", "curl", "http://localhost:8080"]
52 | timeout: 5s
53 | retries: 10
54 |
55 | fleetspeak-client:
56 | build:
57 | context: .
58 | dockerfile: ../shared/fleetspeak-client/Dockerfile
59 | hostname: fleetspeak-client
60 | depends_on:
61 | fleetspeak-server:
62 | condition: service_healthy
63 | entrypoint: ["/app/bin/client", "-config", "/config/fleetspeak-client/config.textproto", "-alsologtostderr"]
64 | volumes:
65 | - "./config:/config"
66 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/fleetspeak-client/communicator.txt:
--------------------------------------------------------------------------------
1 | prefer_http2: true
2 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/fleetspeak-client/config.textproto:
--------------------------------------------------------------------------------
1 | server: "fleetspeak-frontend:10000"
2 | trusted_certs:"FRONTEND_CERTIFICATE"
3 | client_label: ""
4 | filesystem_handler: {
5 | configuration_directory:"/config/fleetspeak-client"
6 | state_file:"/fleetspeak-client.state"
7 | }
8 | streaming:true
9 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/fleetspeak-client/textservices/hello.service:
--------------------------------------------------------------------------------
1 | name: "hello"
2 | factory: "Daemon"
3 | config: {
4 | [type.googleapis.com/fleetspeak.daemonservice.Config]: {
5 | argv: "/venv/FSENV/bin/python"
6 | argv: "/config/hello.py"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/fleetspeak-server/components.textproto:
--------------------------------------------------------------------------------
1 | mysql_data_source_name:"fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
2 | https_config: {
3 | listen_address: "0.0.0.0:9090"
4 | certificates:"FRONTEND_CERTIFICATE"
5 | key:"FRONTEND_KEY"
6 | frontend_config: {
7 | cleartext_xfcc_config: {
8 | client_certificate_header: "x-forwarded-client-cert"
9 | }
10 | }
11 | }
12 | admin_config: {
13 | listen_address: "0.0.0.0:9091"
14 | }
15 | health_check_config: {
16 | listen_address: "0.0.0.0:8080"
17 | }
18 | notification_use_http_notifier:false
19 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/fleetspeak-server/services.textproto:
--------------------------------------------------------------------------------
1 | services {
2 | name: "greeter"
3 | factory: "GRPC"
4 | config: {
5 | [type.googleapis.com/fleetspeak.grpcservice.Config] {
6 | target: "greeter:1337"
7 | insecure: true
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/fleetspeak.textproto:
--------------------------------------------------------------------------------
1 | configuration_name: "Example"
2 |
3 | components_config {
4 |
5 | mysql_data_source_name: "fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
6 |
7 | https_config {
8 | listen_address: "fleetspeak-server:9090"
9 | }
10 |
11 | admin_config {
12 | listen_address: "fleetspeak-server:9091"
13 | }
14 | }
15 |
16 | public_host_port: "fleetspeak-server:9090"
17 |
18 | trusted_cert_file: "/config/fleetspeak-server/ca.pem"
19 | trusted_cert_key_file: "/config/fleetspeak-server/ca-key.pem"
20 |
21 | server_cert_file: "/config/fleetspeak-server/server.pem"
22 | server_cert_key_file: "/config/fleetspeak-server/server-key.pem"
23 |
24 | server_component_configuration_file: "/config/fleetspeak-server/components.textproto"
25 | linux_client_configuration_file: "/config/fleetspeak-client/config.textproto"
26 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/hello.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from absl import app
16 | from fleetspeak.client_connector.connector import FleetspeakConnection
17 | from fleetspeak.src.common.proto.fleetspeak.common_pb2 import Message
18 | from google.protobuf.wrappers_pb2 import StringValue
19 |
20 |
21 | def main(argv):
22 | del argv # Unused.
23 |
24 | conn = FleetspeakConnection(version="0.0.1")
25 | while True:
26 | request, _ = conn.Recv()
27 |
28 | data = StringValue()
29 | request.data.Unpack(data)
30 |
31 | data.value = f"Hello {data.value}!"
32 |
33 | response = Message()
34 | response.destination.service_name = request.source.service_name
35 | response.data.Pack(data)
36 |
37 | conn.Send(response)
38 |
39 |
40 | if __name__ == "__main__":
41 | app.run(main)
42 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/config/hello.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | /venv/FSENV/bin/python /config/hello.py
3 |
--------------------------------------------------------------------------------
/sandboxes/cleartext-xfcc-mode/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | mysql-server:
4 | image: mysql:8.2
5 | restart: always
6 | hostname: mysql-server
7 | environment:
8 | MYSQL_DATABASE: 'fleetspeak'
9 | MYSQL_USER: 'fleetspeak-user'
10 | MYSQL_PASSWORD: 'fleetspeak-password'
11 | MYSQL_ROOT_PASSWORD: 'password'
12 | ports:
13 | - '3306:3306'
14 | expose:
15 | - '3306'
16 | healthcheck:
17 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
18 | timeout: 5s
19 | retries: 10
20 |
21 | front-envoy:
22 | build:
23 | context: .
24 | dockerfile: ../shared/envoy/Dockerfile
25 | args:
26 | ENVOY_CONFIG: ./envoy-https-http.yaml
27 | hostname: fleetspeak-frontend
28 | ports:
29 | - "10000:10000"
30 |
31 | fleetspeak-server:
32 | build:
33 | context: .
34 | dockerfile: ../shared/fleetspeak-server/Dockerfile
35 | hostname: fleetspeak-server
36 | depends_on:
37 | mysql-server:
38 | condition: service_healthy
39 | entrypoint: ["/app/bin/server", "-components_config", "/config/fleetspeak-server/components.textproto", "-services_config", "/config/fleetspeak-server/services.textproto", "-alsologtostderr"]
40 | volumes:
41 | - "./config:/config"
42 | ports:
43 | - '9090:9090'
44 | - '9091:9091'
45 | - '8080:8080'
46 | expose:
47 | - '9090'
48 | - '9091'
49 | - '8080'
50 | healthcheck:
51 | test: ["CMD", "curl", "http://localhost:8080"]
52 | timeout: 5s
53 | retries: 10
54 |
55 | fleetspeak-client:
56 | build:
57 | context: .
58 | dockerfile: ../shared/fleetspeak-client/Dockerfile
59 | hostname: fleetspeak-client
60 | depends_on:
61 | fleetspeak-server:
62 | condition: service_healthy
63 | entrypoint: ["/app/bin/client", "-config", "/config/fleetspeak-client/config.textproto", "-alsologtostderr"]
64 | volumes:
65 | - "./config:/config"
66 |
--------------------------------------------------------------------------------
/sandboxes/createConfig.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | openssl ecparam -list_curves
3 |
4 | # generate a private key for a curve
5 | openssl ecparam -name prime256v1 -genkey -noout -out key.pem
6 |
7 | # optional: generate corresponding public key
8 | openssl ec -in key.pem -pubout -out public-key.pem
9 |
10 | # create a self-signed certificate
11 | openssl req -new -x509 -key key.pem -out cert.pem -days 365 -subj "/C=AU/CN=fleetspeak-frontend" -addext "subjectAltName = DNS:fleetspeak-frontend"
12 |
13 | FRONTEND_CERTIFICATE=$(sed ':a;N;$!ba;s/\n/\\\\n/g' cert.pem)
14 | FRONTEND_KEY=$(sed ':a;N;$!ba;s/\n/\\\\n/g' key.pem)
15 |
16 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./cleartext-header-mode/config/fleetspeak-client/config.textproto
17 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./cleartext-xfcc-mode/config/fleetspeak-client/config.textproto
18 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./direct-mtls-mode/config/fleetspeak-client/config.textproto
19 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./https-header-mode/config/fleetspeak-client/config.textproto
20 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./passthrough-mode/config/fleetspeak-client/config.textproto
21 |
22 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./cleartext-header-mode/config/fleetspeak-server/components.textproto
23 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./cleartext-xfcc-mode/config/fleetspeak-server/components.textproto
24 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./direct-mtls-mode/config/fleetspeak-server/components.textproto
25 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./https-header-mode/config/fleetspeak-server/components.textproto
26 | sed -i 's@FRONTEND_CERTIFICATE@'"$FRONTEND_CERTIFICATE"'@' ./passthrough-mode/config/fleetspeak-server/components.textproto
27 |
28 | sed -i 's@FRONTEND_KEY@'"$FRONTEND_KEY"'@' ./cleartext-header-mode/config/fleetspeak-server/components.textproto
29 | sed -i 's@FRONTEND_KEY@'"$FRONTEND_KEY"'@' ./cleartext-xfcc-mode/config/fleetspeak-server/components.textproto
30 | sed -i 's@FRONTEND_KEY@'"$FRONTEND_KEY"'@' ./direct-mtls-mode/config/fleetspeak-server/components.textproto
31 | sed -i 's@FRONTEND_KEY@'"$FRONTEND_KEY"'@' ./https-header-mode/config/fleetspeak-server/components.textproto
32 | sed -i 's@FRONTEND_KEY@'"$FRONTEND_KEY"'@' ./passthrough-mode/config/fleetspeak-server/components.textproto
33 |
34 | cp cert.pem key.pem ./cleartext-header-mode/
35 | cp cert.pem key.pem ./cleartext-xfcc-mode/
36 | cp cert.pem key.pem ./direct-mtls-mode/
37 | cp cert.pem key.pem ./https-header-mode/
38 | cp cert.pem key.pem ./passthrough-mode/
39 |
--------------------------------------------------------------------------------
/sandboxes/diagrams/cleartextHeaderMode_355.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/fleetspeak/dde186c1e913f5160df82afbe2f84bcd72900c1e/sandboxes/diagrams/cleartextHeaderMode_355.png
--------------------------------------------------------------------------------
/sandboxes/diagrams/cleartextXfccMode_355.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/fleetspeak/dde186c1e913f5160df82afbe2f84bcd72900c1e/sandboxes/diagrams/cleartextXfccMode_355.png
--------------------------------------------------------------------------------
/sandboxes/diagrams/directMode_355.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/fleetspeak/dde186c1e913f5160df82afbe2f84bcd72900c1e/sandboxes/diagrams/directMode_355.png
--------------------------------------------------------------------------------
/sandboxes/diagrams/httpsHeaderMode_355.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/fleetspeak/dde186c1e913f5160df82afbe2f84bcd72900c1e/sandboxes/diagrams/httpsHeaderMode_355.png
--------------------------------------------------------------------------------
/sandboxes/diagrams/passthroughMode_355.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/fleetspeak/dde186c1e913f5160df82afbe2f84bcd72900c1e/sandboxes/diagrams/passthroughMode_355.png
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/fleetspeak-client/communicator.txt:
--------------------------------------------------------------------------------
1 | prefer_http2: true
2 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/fleetspeak-client/config.textproto:
--------------------------------------------------------------------------------
1 | server:"fleetspeak-frontend:9090"
2 | trusted_certs:"FRONTEND_CERTIFICATE"
3 | client_label:""
4 | filesystem_handler: {
5 | configuration_directory:"/config/fleetspeak-client"
6 | state_file:"/fleetspeak-client.state"
7 | }
8 | streaming:true
9 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/fleetspeak-client/textservices/hello.service:
--------------------------------------------------------------------------------
1 | name: "hello"
2 | factory: "Daemon"
3 | config: {
4 | [type.googleapis.com/fleetspeak.daemonservice.Config]: {
5 | argv: "/venv/FSENV/bin/python"
6 | argv: "/config/hello.py"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/fleetspeak-server/components.textproto:
--------------------------------------------------------------------------------
1 | mysql_data_source_name:"fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
2 | https_config: {
3 | listen_address: "0.0.0.0:9090"
4 | certificates:"FRONTEND_CERTIFICATE"
5 | key:"FRONTEND_KEY"
6 | }
7 | admin_config: {
8 | listen_address: "0.0.0.0:9091"
9 | }
10 | health_check_config: {
11 | listen_address: "0.0.0.0:8080"
12 | }
13 | notification_use_http_notifier:false
14 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/fleetspeak-server/services.textproto:
--------------------------------------------------------------------------------
1 | services {
2 | name: "greeter"
3 | factory: "GRPC"
4 | config: {
5 | [type.googleapis.com/fleetspeak.grpcservice.Config] {
6 | target: "greeter:1337"
7 | insecure: true
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/fleetspeak.textproto:
--------------------------------------------------------------------------------
1 | configuration_name: "Example"
2 |
3 | components_config {
4 |
5 | mysql_data_source_name: "fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
6 |
7 | https_config {
8 | listen_address: "fleetspeak-server:9090"
9 | }
10 |
11 | admin_config {
12 | listen_address: "fleetspeak-server:9091"
13 | }
14 | }
15 |
16 | public_host_port: "fleetspeak-server:9090"
17 |
18 | trusted_cert_file: "/config/fleetspeak-server/ca.pem"
19 | trusted_cert_key_file: "/config/fleetspeak-server/ca-key.pem"
20 |
21 | server_cert_file: "/config/fleetspeak-server/server.pem"
22 | server_cert_key_file: "/config/fleetspeak-server/server-key.pem"
23 |
24 | server_component_configuration_file: "/config/fleetspeak-server/components.textproto"
25 | linux_client_configuration_file: "/config/fleetspeak-client/config.textproto"
26 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/hello.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from absl import app
16 | from fleetspeak.client_connector.connector import FleetspeakConnection
17 | from fleetspeak.src.common.proto.fleetspeak.common_pb2 import Message
18 | from google.protobuf.wrappers_pb2 import StringValue
19 |
20 |
21 | def main(argv):
22 | del argv # Unused.
23 |
24 | conn = FleetspeakConnection(version="0.0.1")
25 | while True:
26 | request, _ = conn.Recv()
27 |
28 | data = StringValue()
29 | request.data.Unpack(data)
30 |
31 | data.value = f"Hello {data.value}!"
32 |
33 | response = Message()
34 | response.destination.service_name = request.source.service_name
35 | response.data.Pack(data)
36 |
37 | conn.Send(response)
38 |
39 |
40 | if __name__ == "__main__":
41 | app.run(main)
42 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/config/hello.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | /venv/FSENV/bin/python /config/hello.py
3 |
--------------------------------------------------------------------------------
/sandboxes/direct-mtls-mode/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | mysql-server:
4 | image: mysql:8.2
5 | restart: always
6 | hostname: mysql-server
7 | environment:
8 | MYSQL_DATABASE: 'fleetspeak'
9 | MYSQL_USER: 'fleetspeak-user'
10 | MYSQL_PASSWORD: 'fleetspeak-password'
11 | MYSQL_ROOT_PASSWORD: 'password'
12 | ports:
13 | - '3306:3306'
14 | expose:
15 | - '3306'
16 | healthcheck:
17 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
18 | timeout: 5s
19 | retries: 10
20 |
21 | fleetspeak-server:
22 | build:
23 | context: .
24 | dockerfile: ../shared/fleetspeak-server/Dockerfile
25 | hostname: fleetspeak-frontend
26 | depends_on:
27 | mysql-server:
28 | condition: service_healthy
29 | entrypoint: ["/app/bin/server", "-components_config", "/config/fleetspeak-server/components.textproto", "-services_config", "/config/fleetspeak-server/services.textproto", "-alsologtostderr"]
30 | volumes:
31 | - "./config:/config"
32 | ports:
33 | - '9090:9090'
34 | - '9091:9091'
35 | - '8080:8080'
36 | expose:
37 | - '9090'
38 | - '9091'
39 | - '8080'
40 | healthcheck:
41 | test: ["CMD", "curl", "http://localhost:8080"]
42 | timeout: 5s
43 | retries: 10
44 |
45 | fleetspeak-client:
46 | build:
47 | context: .
48 | dockerfile: ../shared/fleetspeak-client/Dockerfile
49 | hostname: fleetspeak-client
50 | depends_on:
51 | fleetspeak-server:
52 | condition: service_healthy
53 | entrypoint: ["/app/bin/client", "-config", "/config/fleetspeak-client/config.textproto", "-alsologtostderr"]
54 | volumes:
55 | - "./config:/config"
56 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/fleetspeak-client/communicator.txt:
--------------------------------------------------------------------------------
1 | prefer_http2: true
2 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/fleetspeak-client/config.textproto:
--------------------------------------------------------------------------------
1 | server: "fleetspeak-frontend:10000"
2 | client_certificate_header: "client-certificate"
3 | trusted_certs:"FRONTEND_CERTIFICATE"
4 | client_label: ""
5 | filesystem_handler: {
6 | configuration_directory:"/config/fleetspeak-client"
7 | state_file:"/fleetspeak-client.state"
8 | }
9 | streaming:true
10 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/fleetspeak-client/textservices/hello.service:
--------------------------------------------------------------------------------
1 | name: "hello"
2 | factory: "Daemon"
3 | config: {
4 | [type.googleapis.com/fleetspeak.daemonservice.Config]: {
5 | argv: "/venv/FSENV/bin/python"
6 | argv: "/config/hello.py"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/fleetspeak-server/components.textproto:
--------------------------------------------------------------------------------
1 | mysql_data_source_name:"fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
2 | https_config: {
3 | listen_address: "0.0.0.0:9090"
4 | certificates:"FRONTEND_CERTIFICATE"
5 | key:"FRONTEND_KEY"
6 | frontend_config: {
7 | https_header_checksum_config: {
8 | client_certificate_header: "client-certificate"
9 | client_certificate_checksum_header: "x-client-cert-hash"
10 | }
11 | }
12 | }
13 | admin_config: {
14 | listen_address: "0.0.0.0:9091"
15 | }
16 | health_check_config: {
17 | listen_address: "0.0.0.0:8080"
18 | }
19 | notification_use_http_notifier:false
20 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/fleetspeak-server/services.textproto:
--------------------------------------------------------------------------------
1 | services {
2 | name: "greeter"
3 | factory: "GRPC"
4 | config: {
5 | [type.googleapis.com/fleetspeak.grpcservice.Config] {
6 | target: "greeter:1337"
7 | insecure: true
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/fleetspeak.textproto:
--------------------------------------------------------------------------------
1 | configuration_name: "Example"
2 |
3 | components_config {
4 |
5 | mysql_data_source_name: "fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
6 |
7 | https_config {
8 | listen_address: "fleetspeak-server:9090"
9 | }
10 |
11 | admin_config {
12 | listen_address: "fleetspeak-server:9091"
13 | }
14 | }
15 |
16 | public_host_port: "fleetspeak-server:9090"
17 |
18 | trusted_cert_file: "/config/fleetspeak-server/ca.pem"
19 | trusted_cert_key_file: "/config/fleetspeak-server/ca-key.pem"
20 |
21 | server_cert_file: "/config/fleetspeak-server/server.pem"
22 | server_cert_key_file: "/config/fleetspeak-server/server-key.pem"
23 |
24 | server_component_configuration_file: "/config/fleetspeak-server/components.textproto"
25 | linux_client_configuration_file: "/config/fleetspeak-client/config.textproto"
26 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/hello.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from absl import app
16 | from fleetspeak.client_connector.connector import FleetspeakConnection
17 | from fleetspeak.src.common.proto.fleetspeak.common_pb2 import Message
18 | from google.protobuf.wrappers_pb2 import StringValue
19 |
20 |
21 | def main(argv):
22 | del argv # Unused.
23 |
24 | conn = FleetspeakConnection(version="0.0.1")
25 | while True:
26 | request, _ = conn.Recv()
27 |
28 | data = StringValue()
29 | request.data.Unpack(data)
30 |
31 | data.value = f"Hello {data.value}!"
32 |
33 | response = Message()
34 | response.destination.service_name = request.source.service_name
35 | response.data.Pack(data)
36 |
37 | conn.Send(response)
38 |
39 |
40 | if __name__ == "__main__":
41 | app.run(main)
42 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/config/hello.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | /venv/FSENV/bin/python /config/hello.py
3 |
--------------------------------------------------------------------------------
/sandboxes/https-header-mode/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | mysql-server:
4 | image: mysql:8.2
5 | restart: always
6 | hostname: mysql-server
7 | environment:
8 | MYSQL_DATABASE: 'fleetspeak'
9 | MYSQL_USER: 'fleetspeak-user'
10 | MYSQL_PASSWORD: 'fleetspeak-password'
11 | MYSQL_ROOT_PASSWORD: 'password'
12 | ports:
13 | - '3306:3306'
14 | expose:
15 | - '3306'
16 | healthcheck:
17 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
18 | timeout: 5s
19 | retries: 10
20 |
21 | front-envoy:
22 | build:
23 | context: .
24 | dockerfile: ../shared/envoy/Dockerfile
25 | args:
26 | ENVOY_CONFIG: ./envoy-https-https.yaml
27 | hostname: fleetspeak-frontend
28 | ports:
29 | - "10000:10000"
30 |
31 | fleetspeak-server:
32 | build:
33 | context: .
34 | dockerfile: ../shared/fleetspeak-server/Dockerfile
35 | hostname: fleetspeak-server
36 | depends_on:
37 | mysql-server:
38 | condition: service_healthy
39 | entrypoint: ["/app/bin/server", "-components_config", "/config/fleetspeak-server/components.textproto", "-services_config", "/config/fleetspeak-server/services.textproto", "-alsologtostderr"]
40 | volumes:
41 | - "./config:/config"
42 | ports:
43 | - '9090:9090'
44 | - '9091:9091'
45 | - '8080:8080'
46 | expose:
47 | - '9090'
48 | - '9091'
49 | - '8080'
50 | healthcheck:
51 | test: ["CMD", "curl", "http://localhost:8080"]
52 | timeout: 5s
53 | retries: 10
54 |
55 | fleetspeak-client:
56 | build:
57 | context: .
58 | dockerfile: ../shared/fleetspeak-client/Dockerfile
59 | hostname: fleetspeak-client
60 | depends_on:
61 | fleetspeak-server:
62 | condition: service_healthy
63 | entrypoint: ["/app/bin/client", "-config", "/config/fleetspeak-client/config.textproto", "-alsologtostderr"]
64 | volumes:
65 | - "./config:/config"
66 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/fleetspeak-client/communicator.txt:
--------------------------------------------------------------------------------
1 | prefer_http2: true
2 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/fleetspeak-client/config.textproto:
--------------------------------------------------------------------------------
1 | server:"fleetspeak-frontend:10003"
2 | trusted_certs:"FRONTEND_CERTIFICATE"
3 | client_label:""
4 | filesystem_handler: {
5 | configuration_directory:"/config/fleetspeak-client"
6 | state_file:"/fleetspeak-client.state"
7 | }
8 | streaming:true
9 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/fleetspeak-client/textservices/hello.service:
--------------------------------------------------------------------------------
1 | name: "hello"
2 | factory: "Daemon"
3 | config: {
4 | [type.googleapis.com/fleetspeak.daemonservice.Config]: {
5 | argv: "/venv/FSENV/bin/python"
6 | argv: "/config/hello.py"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/fleetspeak-server/components.textproto:
--------------------------------------------------------------------------------
1 | mysql_data_source_name:"fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
2 | https_config: {
3 | listen_address: "0.0.0.0:9090"
4 | certificates:"FRONTEND_CERTIFICATE"
5 | key:"FRONTEND_KEY"
6 | }
7 | admin_config: {
8 | listen_address: "0.0.0.0:9091"
9 | }
10 | health_check_config: {
11 | listen_address: "0.0.0.0:8080"
12 | }
13 | notification_use_http_notifier:false
14 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/fleetspeak-server/services.textproto:
--------------------------------------------------------------------------------
1 | services {
2 | name: "greeter"
3 | factory: "GRPC"
4 | config: {
5 | [type.googleapis.com/fleetspeak.grpcservice.Config] {
6 | target: "greeter:1337"
7 | insecure: true
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/fleetspeak.textproto:
--------------------------------------------------------------------------------
1 | configuration_name: "Example"
2 |
3 | components_config {
4 |
5 | mysql_data_source_name: "fleetspeak-user:fleetspeak-password@tcp(mysql-server:3306)/fleetspeak"
6 |
7 | https_config {
8 | listen_address: "fleetspeak-server:9090"
9 | }
10 |
11 | admin_config {
12 | listen_address: "fleetspeak-server:9091"
13 | }
14 | }
15 |
16 | public_host_port: "fleetspeak-server:9090"
17 |
18 | trusted_cert_file: "/config/fleetspeak-server/ca.pem"
19 | trusted_cert_key_file: "/config/fleetspeak-server/ca-key.pem"
20 |
21 | server_cert_file: "/config/fleetspeak-server/server.pem"
22 | server_cert_key_file: "/config/fleetspeak-server/server-key.pem"
23 |
24 | server_component_configuration_file: "/config/fleetspeak-server/components.textproto"
25 | linux_client_configuration_file: "/config/fleetspeak-client/config.textproto"
26 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/hello.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from absl import app
16 | from fleetspeak.client_connector.connector import FleetspeakConnection
17 | from fleetspeak.src.common.proto.fleetspeak.common_pb2 import Message
18 | from google.protobuf.wrappers_pb2 import StringValue
19 |
20 |
21 | def main(argv):
22 | del argv # Unused.
23 |
24 | conn = FleetspeakConnection(version="0.0.1")
25 | while True:
26 | request, _ = conn.Recv()
27 |
28 | data = StringValue()
29 | request.data.Unpack(data)
30 |
31 | data.value = f"Hello {data.value}!"
32 |
33 | response = Message()
34 | response.destination.service_name = request.source.service_name
35 | response.data.Pack(data)
36 |
37 | conn.Send(response)
38 |
39 |
40 | if __name__ == "__main__":
41 | app.run(main)
42 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/config/hello.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | /venv/FSENV/bin/python /config/hello.py
3 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | mysql-server:
4 | image: mysql:8.2
5 | restart: always
6 | hostname: mysql-server
7 | environment:
8 | MYSQL_DATABASE: 'fleetspeak'
9 | MYSQL_USER: 'fleetspeak-user'
10 | MYSQL_PASSWORD: 'fleetspeak-password'
11 | MYSQL_ROOT_PASSWORD: 'password'
12 | ports:
13 | - '3306:3306'
14 | expose:
15 | - '3306'
16 | healthcheck:
17 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
18 | timeout: 5s
19 | retries: 10
20 |
21 | front-envoy:
22 | build:
23 | context: .
24 | dockerfile: ../shared/envoy/Dockerfile
25 | args:
26 | ENVOY_CONFIG: ./envoy-https-passthrough.yaml
27 | hostname: fleetspeak-frontend
28 | ports:
29 | - "10003:10003"
30 | expose:
31 | - '10003'
32 |
33 | fleetspeak-server:
34 | build:
35 | context: .
36 | dockerfile: ../shared/fleetspeak-server/Dockerfile
37 | hostname: fleetspeak-server
38 | depends_on:
39 | mysql-server:
40 | condition: service_healthy
41 | entrypoint: ["/app/bin/server", "-components_config", "/config/fleetspeak-server/components.textproto", "-services_config", "/config/fleetspeak-server/services.textproto", "-alsologtostderr"]
42 | volumes:
43 | - "./config:/config"
44 | ports:
45 | - '9090:9090'
46 | - '9091:9091'
47 | - '8080:8080'
48 | expose:
49 | - '9090'
50 | - '9091'
51 | - '8080'
52 | healthcheck:
53 | test: ["CMD", "curl", "http://localhost:8080"]
54 | timeout: 5s
55 | retries: 10
56 |
57 | fleetspeak-client:
58 | build:
59 | context: .
60 | dockerfile: ../shared/fleetspeak-client/Dockerfile
61 | hostname: fleetspeak-client
62 | depends_on:
63 | fleetspeak-server:
64 | condition: service_healthy
65 | entrypoint: ["/app/bin/client", "-config", "/config/fleetspeak-client/config.textproto", "-alsologtostderr"]
66 | volumes:
67 | - "./config:/config"
68 |
--------------------------------------------------------------------------------
/sandboxes/passthrough-mode/envoy-https-passthrough.yaml:
--------------------------------------------------------------------------------
1 | static_resources:
2 | listeners:
3 | - address:
4 | socket_address:
5 | address: 0.0.0.0
6 | port_value: 10003
7 | filter_chains:
8 | - filters:
9 | - name: envoy.filters.network.tcp_proxy
10 | typed_config:
11 | "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
12 | cluster: fleetspeak-server-cluster
13 | stat_prefix: https_passthrough
14 |
15 | clusters:
16 | - name: fleetspeak-server-cluster
17 | type: STRICT_DNS
18 | lb_policy: ROUND_ROBIN
19 | load_assignment:
20 | cluster_name: fleetspeak-server-cluster
21 | endpoints:
22 | - lb_endpoints:
23 | - endpoint:
24 | address:
25 | socket_address:
26 | address: fleetspeak-server
27 | port_value: 9090
28 |
--------------------------------------------------------------------------------
/sandboxes/shared/fleetspeak-client/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | FROM golang:1.22 as builder
15 |
16 | RUN apt update && \
17 | apt install -y python3-venv && \
18 | apt install -y pip && \
19 | apt install -y git
20 |
21 | WORKDIR /
22 |
23 | SHELL ["/bin/bash", "-c"]
24 |
25 | RUN git clone https://github.com/google/fleetspeak.git && \
26 | cd fleetspeak && \
27 | go get -u golang.org/x/lint/golint && \
28 | ./fleetspeak/generate_protos_setup.sh
29 |
30 | ENV PATH="$HOME/.local/bin:$PATH"
31 |
32 | RUN mkdir -p /app/bin
33 |
34 | RUN cd /fleetspeak && \
35 | python3 -m venv /venv/FSENV && \
36 | source /venv/FSENV/bin/activate && \
37 | pip install wheel pytest && \
38 | pip install -e ./fleetspeak_python[test] && \
39 | pip install -e ./frr_python && \
40 | ./fleetspeak/generate_protos.sh && \
41 | go build -o /app/bin/server ./cmd/fleetspeak_server && \
42 | go build -o /app/bin/client ./cmd/fleetspeak_client && \
43 | go build -o /app/bin/fleetspeak_config ./cmd/fleetspeak_config
44 |
45 |
--------------------------------------------------------------------------------
/sandboxes/shared/fleetspeak-server/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | FROM golang:1.22 as builder
15 |
16 | RUN apt update && \
17 | apt install -y python3-venv && \
18 | apt install -y pip && \
19 | apt install -y git
20 |
21 | WORKDIR /
22 |
23 | SHELL ["/bin/bash", "-c"]
24 |
25 | RUN git clone https://github.com/google/fleetspeak.git && \
26 | cd fleetspeak && \
27 | go get -u golang.org/x/lint/golint && \
28 | ./fleetspeak/generate_protos_setup.sh
29 |
30 | ENV PATH="$HOME/.local/bin:$PATH"
31 |
32 | ENV GOBIN=/fleetspeak-bin
33 |
34 | RUN mkdir -p ${GOBIN}
35 |
36 | RUN cd /fleetspeak && \
37 | python3 -m venv $HOME/.venv/FSENV && \
38 | source $HOME/.venv/FSENV/bin/activate && \
39 | pip install wheel pytest && \
40 | pip install -e ./fleetspeak_python[test] && \
41 | pip install -e ./frr_python && \
42 | ./fleetspeak/generate_protos.sh && \
43 | go install ./cmd/fleetspeak_server ./cmd/fleetspeak_client \
44 | ./cmd/fleetspeak_config
45 |
46 | FROM golang:1.22
47 |
48 | RUN mkdir -p /app/bin
49 |
50 | COPY --from=builder /fleetspeak-bin/fleetspeak_server /app/bin/server
51 | COPY --from=builder /fleetspeak-bin/fleetspeak_client /app/bin/client
52 | COPY --from=builder /fleetspeak-bin/fleetspeak_config /app/bin/
53 |
--------------------------------------------------------------------------------
/sandboxes/shared/greeter/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | FROM golang:1.22 as builder
15 |
16 | RUN apt update && \
17 | apt install -y python3-venv && \
18 | apt install -y pip && \
19 | apt install -y git
20 |
21 | WORKDIR /
22 |
23 | SHELL ["/bin/bash", "-c"]
24 |
25 | RUN git clone https://github.com/google/fleetspeak.git
26 |
27 | RUN cd /fleetspeak && \
28 | python3 -m venv /venv/FSENV && \
29 | source /venv/FSENV/bin/activate && \
30 | pip install wheel pytest && \
31 | pip install -e ./fleetspeak_python[test] && \
32 | pip install -e ./frr_python
33 |
34 | COPY greeter.py .
35 |
--------------------------------------------------------------------------------
/sandboxes/shared/greeter/greeter.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Google Inc.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | import binascii
15 | import logging
16 |
17 | from absl import app
18 | from absl import flags
19 | from fleetspeak.server_connector.connector import InsecureGRPCServiceClient
20 | from fleetspeak.src.common.proto.fleetspeak.common_pb2 import Message
21 | from google.protobuf.wrappers_pb2 import StringValue
22 |
23 |
24 | FLAGS = flags.FLAGS
25 |
26 | flags.DEFINE_string(
27 | name="client_id",
28 | default="",
29 | help="An id of the client to send the messages to.",
30 | )
31 |
32 |
33 | def listener(message, context):
34 | del context # Unused
35 |
36 | data = StringValue()
37 | message.data.Unpack(data)
38 | logging.info(f"RESPONSE: {data.value}")
39 |
40 |
41 | def main(argv=None):
42 | del argv # Unused.
43 |
44 | service_client = InsecureGRPCServiceClient("greeter")
45 | service_client.Listen(listener)
46 |
47 | while True:
48 | data = StringValue()
49 | data.value = input("Enter your name: ")
50 |
51 | request = Message()
52 | request.destination.client_id = binascii.unhexlify(FLAGS.client_id)
53 | request.destination.service_name = "hello"
54 | request.data.Pack(data)
55 |
56 | service_client.Send(request)
57 |
58 |
59 | if __name__ == "__main__":
60 | app.run(main)
61 |
--------------------------------------------------------------------------------
/spanner-setup/Dockerfile.dev:
--------------------------------------------------------------------------------
1 | FROM golang:1.22 AS builder
2 |
3 | RUN apt-get update && \
4 | apt install -y python3-venv && \
5 | apt install -y pip && \
6 | apt install -y vim && \
7 | apt-get install -y python-is-python3
8 |
9 | SHELL ["/bin/bash", "-c"]
10 |
11 | COPY . /fleetspeak
12 |
13 | ENV GOBIN=/fleetspeak/bin
14 | RUN mkdir -p $GOBIN
15 | RUN cd /fleetspeak && go install ./...
16 |
17 | RUN cd /fleetspeak && \
18 | python3 -m venv /venv/FSENV && \
19 | source /venv/FSENV/bin/activate && \
20 | pip install wheel pytest && \
21 | pip install -e ./fleetspeak_python[test] && \
22 | pip install -e ./frr_python
23 |
24 | WORKDIR /
25 |
26 | RUN cd /fleetspeak && \
27 | git clone https://github.com/googleapis/python-pubsub.git && \
28 | cd python-pubsub/samples/snippets && \
29 | source /venv/FSENV/bin/activate && \
30 | pip install -r requirements.txt
31 |
32 | ENV FLEETSPEAK_BIN=/fleetspeak/bin
33 |
34 | RUN ln -s /fleetspeak/bin/fleetspeak_server $FLEETSPEAK_BIN/server
35 | RUN ln -s /fleetspeak/bin/fleetspeak_client $FLEETSPEAK_BIN/client
36 |
37 | ENV PATH="$FLEETSPEAK_BIN:$PATH"
38 |
39 | ENTRYPOINT [ "server" ]
--------------------------------------------------------------------------------
/spanner-setup/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | mysql-db:
3 | image: mysql:8.2
4 | restart: always
5 | hostname: mysql-db
6 | environment:
7 | MYSQL_DATABASE: 'fleetspeak'
8 | MYSQL_USER: 'fleetspeak-user'
9 | MYSQL_PASSWORD: 'fleetspeak-password'
10 | MYSQL_ROOT_PASSWORD: 'password'
11 | ports:
12 | - '3306:3306'
13 | expose:
14 | - '3306'
15 | healthcheck:
16 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
17 | timeout: 5s
18 | retries: 10
19 |
20 | fleetspeak:
21 | build:
22 | context: ../
23 | dockerfile: ./spanner-setup/Dockerfile.dev
24 | hostname: fleetspeak-test
25 | depends_on:
26 | mysql-db:
27 | condition: service_healthy
28 | entrypoint: ["tail", "-F", "/fleetspeak/spanner-setup/setup.sh"]
29 | volumes:
30 | - "/home/user/.config/gcloud/:/root/.config/gcloud"
31 |
32 | pubsub-emulator:
33 | image: google/cloud-sdk:emulators
34 | restart: always
35 | hostname: pubsub-emulator
36 | entrypoint: ["/google-cloud-sdk/bin/gcloud", "beta", "emulators", "pubsub", "start", "--project=spanner-emulator-project", "--host-port=0.0.0.0:8085"]
37 | ports:
38 | - '8085:8085'
39 | expose:
40 | - '8085'
41 |
42 | spanner-emulator:
43 | image: gcr.io/cloud-spanner-emulator/emulator
44 | restart: always
45 | hostname: spanner-emulator
46 | ports:
47 | - '9010:9010'
48 | - '9020:9020'
49 | expose:
50 | - '9010'
51 | - '9020'
--------------------------------------------------------------------------------
/spanner-setup/fleetspeak.pb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/fleetspeak/dde186c1e913f5160df82afbe2f84bcd72900c1e/spanner-setup/fleetspeak.pb
--------------------------------------------------------------------------------
/terraform/README.md:
--------------------------------------------------------------------------------
1 | # Using Terraform to run Fleetspeak End-to-End testing in Google Cloud
2 |
3 | ## Installing Terraform
4 |
5 | Please follow
6 | [these instructions](https://www.terraform.io/intro/getting-started/install.html)
7 | to install Terraform binary on your machine.
8 |
9 | ## Setting up a Google Cloud Project
10 |
11 | 1. Create a new project in Google Cloud Platform console
12 | ([link](https://console.cloud.google.com/project)).
13 | 1. Enable billing for the project
14 | ([link](https://support.google.com/cloud/answer/6293499#enable-billing)).
15 | 1. Enable Compute Engine and Cloud SQL APIs
16 | ([link](https://console.cloud.google.com/flows/enableapi?apiid=compute_component,sqladmin)).
17 |
18 | ## Instrumenting Terraform with credentials
19 |
20 | 1. Install Google Cloud SDK ([link](https://cloud.google.com/sdk/install)).
21 | 2. Obtain Google Cloud credentials by running the following: `bash gcloud auth
22 | application-default login` Your credentials will be saved to a file
23 | `~/.config/gcloud/application_default_credentials.json`. It will be used by
24 | terraform.
25 |
26 | ## Running Terraform
27 |
28 | 1. `cd` to terraform directory
29 | 2. Run the following to initialize Terraform: `bash terraform init`
30 | 3. Then run the following to start installation: `bash terraform apply -var
31 | "project_name=*your_project_name*"`
32 |
33 | By default 1 fleetspeak server and 1 client will be started. You can specify
34 | these numbers with terraform variables: `bash terraform apply -var
35 | "project_name=*your_project_name*" -var "num_servers=2" -var "num_clients=3"`
36 |
37 | If you run the installation in the internal Google Cloud, the default image of
38 | virtual machines may be not allowed. In this case run `terraform apply` with the
39 | additional variable as following: `bash terraform apply -var
40 | "project_name=*your_project_name*" -var
41 | "vm_image=projects/eip-images/global/images/ubuntu-1804-lts-drawfork-v20200208"`
42 |
43 | ## Viewing tests results
44 |
45 | After all the tests are completed, the `results.txt` file will be uploaded into
46 | the bucket created by Terraform
47 | ([link](https://console.cloud.google.com/storage)).
48 |
49 | ## Destroying resources
50 |
51 | When tests are finished, destroy all the resources by running `bash terraform
52 | destroy -var "project_name=*your_project_name*"`
53 |
--------------------------------------------------------------------------------
/terraform/cloudtesting/end_to_end_test.go:
--------------------------------------------------------------------------------
1 | package cloudtesting_test
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "io/ioutil"
7 | "os"
8 | "path/filepath"
9 | "strings"
10 | "testing"
11 | "time"
12 |
13 | "github.com/google/fleetspeak/fleetspeak/src/e2etesting/setup"
14 | "github.com/google/fleetspeak/fleetspeak/src/e2etesting/tests"
15 | )
16 |
17 | var (
18 | numClients = flag.Int("num_clients", 0, "Number of clients")
19 | masterServerAddress = flag.String("ms_address", "", "Address of master server")
20 | serversFile = flag.String("servers_file", "", "File with server hosts")
21 | )
22 |
23 | func TestCloudEndToEnd(t *testing.T) {
24 | flag.Parse()
25 |
26 | if *numClients == 0 {
27 | t.Skip("num_clients flag is required to run this test.")
28 | }
29 | if *masterServerAddress == "" {
30 | t.Skip("ms_address flag is required to run this test.")
31 | }
32 | if *serversFile == "" {
33 | t.Skip("servers_file flag is required to run this test.")
34 | }
35 |
36 | wd, err := os.Getwd()
37 | if err != nil {
38 | t.Fatalf("Failed to get working directory: %v", err)
39 | }
40 | err = os.Chdir(filepath.Dir(filepath.Dir(wd)))
41 | if err != nil {
42 | t.Fatal("Failed to cd to fleetspeak directory")
43 | }
44 |
45 | dat, err := ioutil.ReadFile(*serversFile)
46 | if err != nil {
47 | t.Fatalf("Failed to read serversFile: %v", err)
48 | }
49 | serverHosts := strings.Fields(string(dat))
50 |
51 | startTime := time.Now()
52 | var clientIDs []string
53 |
54 | for range 20 {
55 | // All clients that connected more than 30 minutes ago are considered inactive (not newly connected)
56 | clientIDs, err = setup.WaitForNewClientIDs(fmt.Sprintf("%v:6061", serverHosts[0]), startTime.Add(-time.Minute*30), *numClients)
57 | if err == nil {
58 | break
59 | }
60 | if time.Now().After(startTime.Add(time.Minute * 10)) {
61 | t.Fatalf("Not all clients connected (connected: %v, expected: %v, connected clients: %v): %v", len(clientIDs), *numClients, clientIDs, err)
62 | }
63 | }
64 |
65 | tests.RunTests(t, *masterServerAddress, clientIDs)
66 | }
67 |
--------------------------------------------------------------------------------
/terraform/fleetspeak_configurator/build_configs.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "io/ioutil"
7 | "os"
8 | "strings"
9 |
10 | "github.com/google/fleetspeak/fleetspeak/src/e2etesting/setup"
11 | )
12 |
13 | var (
14 | configDir = flag.String("config_dir", "", "Directory to put config files")
15 | numClients = flag.Int("num_clients", 1, "Number of clients")
16 | serversFile = flag.String("servers_file", "", "File with server hosts")
17 | serverFrontendAddress = flag.String("frontend_address", "", "Frontend address for clients to connect")
18 | mysqlAddress = flag.String("mysql_address", "", "MySQL server address")
19 | mysqlDatabase = flag.String("mysql_database", "", "MySQL database name to use")
20 | mysqlUsername = flag.String("mysql_username", "", "MySQL username to use")
21 | mysqlPassword = flag.String("mysql_password", "", "MySQL password to use")
22 | )
23 |
24 | func run() error {
25 | dat, err := ioutil.ReadFile(*serversFile)
26 | if err != nil {
27 | return fmt.Errorf("Failed to read serversFile: %v", err)
28 | }
29 | serverHosts := strings.Fields(string(dat))
30 |
31 | err = setup.BuildConfigurations(*configDir, serverHosts, *serverFrontendAddress, *numClients,
32 | setup.MysqlCredentials{
33 | Host: *mysqlAddress,
34 | Password: *mysqlPassword,
35 | Username: *mysqlUsername,
36 | Database: *mysqlDatabase,
37 | })
38 | if err != nil {
39 | return fmt.Errorf("Failed to build configs: %v", err)
40 | }
41 |
42 | return nil
43 | }
44 |
45 | func main() {
46 | flag.Parse()
47 | err := run()
48 | if err != nil {
49 | fmt.Println(err)
50 | os.Exit(1)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/terraform/fs_client_start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | touch communicator.txt
6 | touch client.state
7 | mkdir services
8 |
9 | export PATH=/snap/bin:$PATH
10 | ln -fs /usr/bin/python3 /usr/bin/python
11 |
12 | # apt_install command_to_check package_name
13 | function apt_install {
14 | while [[ ! `command -v $1` ]];
15 | do
16 | apt-get -y update ||:
17 | apt-get -y install $2 ||:
18 | sleep 3
19 | done
20 | }
21 |
22 | #cp_from_bucket source_url destination
23 | function cp_from_bucket {
24 | mkdir -p $(dirname $2)
25 | while [[ (! -f $2) && (! -e $2) ]]
26 | do
27 | gsutil cp -r $1 $(dirname $2) ||:
28 | sleep 5
29 | done
30 | }
31 |
32 | apt_install pip3 python3-pip
33 | cp_from_bucket ${storage_bucket_url}/frr_python/wheel frr_python/wheel
34 | pip3 install --target=frr_python frr_python/wheel/*
35 | cp_from_bucket ${storage_bucket_url}/bin/client ./client
36 | cp_from_bucket ${storage_bucket_url}/protos/frr.textproto textservices/frr.textproto
37 | cp_from_bucket ${storage_bucket_url}/client_configs/linux_client.config linux_client.config
38 | touch client${self_index}.ready
39 | gsutil cp client${self_index}.ready ${storage_bucket_url}/started_components/
40 |
41 | chmod +x client
42 |
43 | ./client -logtostderr -config "linux_client.config"
44 |
--------------------------------------------------------------------------------
/terraform/fs_server_start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | # apt_install command_to_check package_name
6 | function apt_install {
7 | while [[ ! `command -v $1` ]];
8 | do
9 | apt-get -y update ||:
10 | apt-get -y install $2 ||:
11 | sleep 3
12 | done
13 | }
14 |
15 | apt_install pip3 python3-pip
16 | apt_install mysql mysql-client
17 |
18 | export PATH=/snap/bin:$PATH
19 |
20 | wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O ./cloud_sql_proxy
21 | chmod +x ./cloud_sql_proxy
22 |
23 | ./cloud_sql_proxy -instances=${mysql_instance_connection_name}=tcp:3306 &
24 |
25 | ln -fs /usr/bin/python3 /usr/bin/python
26 |
27 | #cp_from_bucket source_url destination
28 | function cp_from_bucket {
29 | mkdir -p $(dirname $2)
30 | while [[ (! -f $2) && (! -e $2) ]]
31 | do
32 | gsutil cp -r $1 $(dirname $2) ||:
33 | sleep 5
34 | done
35 | }
36 |
37 | cp_from_bucket ${storage_bucket_url}/frr_python/wheel frr_python/wheel
38 | pip3 install --target=frr_python frr_python/wheel/*
39 | cp_from_bucket ${storage_bucket_url}/bin/server ./server
40 | cp_from_bucket ${storage_bucket_url}/server_configs/server${self_index}.config ./server${self_index}.config
41 | cp_from_bucket ${storage_bucket_url}/server_configs/server${self_index}.services.config ./server${self_index}.services.config
42 | touch server${self_index}.ready
43 | gsutil cp server${self_index}.ready ${storage_bucket_url}/started_components/
44 |
45 | chmod +x server
46 |
47 | ./server -logtostderr -components_config "server${self_index}.config" -services_config "server${self_index}.services.config" &
48 | python3 frr_python/frr_server.py --master_server_address=${master_server_host}:6059 --fleetspeak_message_listen_address=${self_host}:6062 --fleetspeak_server=${self_host}:6061
49 |
--------------------------------------------------------------------------------
/terraform/master_server_start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | while ! gsutil cp ${storage_bucket_url}/bin/frr_master_server_main ./; do
6 | sleep 10
7 | done
8 |
9 | chmod +x frr_master_server_main
10 |
11 | ./frr_master_server_main --listen_address=${master_server_host}:6059 --admin_address=${admin_host}:6061
12 |
--------------------------------------------------------------------------------