A Packet Source is a Proxylity resource that allows your application to send UDP packets to remote clients without waiting for those clients to send a request first. Your application publishes messages to an SNS topic in your AWS account; Proxylity receives them and delivers the corresponding egress packets through a bound Listener.
This complements the standard Destination model, which can only generate egress packets as a synchronous reply to an inbound packet.
Use a Packet Source whenever your application needs to originate egress traffic that is not triggered by an inbound packet. Common examples:
For use cases that do start with an inbound packet — for example, a Lambda function that processes a packet and responds immediately — a synchronous Lambda Destination or EXPRESS Step Functions Destination is simpler and does not require a Packet Source.
When you create a Custom::ProxylityUdpGatewayPacketSource resource, Proxylity uses the IAM role
you provide to subscribe its delivery queues to your SNS topic. From that point:
Because Proxylity sends packets through the Listener's own network addresses, clients see traffic arriving from the same endpoint they use for inbound packets. This ensures firewall and NAT compatibility.
For a standard UDP Listener, a sourced packet requires only a destination address, port, and payload. The
Remote object in each message entry specifies where to send the packet:
{
"Messages": [
{
"Data": "AQIDBA==",
"Remote": {
"Address": "203.0.113.42",
"Port": 4567
}
}
]
}
Note:Because firewall and NAT rules may have short timeouts after periods of inactivity, it's important to ensure that your Packet Source either sends periodic keepalive packets to maintain the session or routing is in place to route return traffic appropriately.
The Data field contains the raw UDP payload. The default encoding is base64, but you
can specify a different Formatter to match your application's needs. All formatters supported
by Destinations are supported here: base64, hex, utf8,
ascii, and coap.
WireGuard Listeners encrypt all traffic using the WireGuard protocol. Sourcing packets through a WireGuard
Listener requires additional fields so Proxylity can select the correct peer session and encrypt the
outgoing packet. WireGuard endpoints should be configured with an appropriate PersistentKeepalive interval to maintain the session for return traffic.
Set Remote.PeerKey to the base64-encoded WireGuard public key of the target peer (copied from a previous inbound packet or otherwise stored). Proxylity
uses this key to look up the WireGuard session established by that peer and encrypt the sourced packet
before delivery. If no session exists for the given key, the packet is discarded.
{
"Messages": [
{
"Data": "AQIDBA==",
"Remote": {
"Address": "203.0.113.42",
"Port": 51820,
"PeerKey": "base64encodedWireGuardPublicKey=="
}
}
]
}
When a WireGuard Listener has
DecapsulatedDelivery enabled,
inbound packets have their WireGuard tunnel headers stripped before delivery to Destinations, exposing the
original inner IP/UDP frame. Sourcing packets back through such a Listener requires the reverse: Proxylity
must re-encapsulate the payload into an inner IP/UDP frame before encrypting and sending it via
WireGuard.
Provide an Inner block in the message to supply the inner IP addressing. Note that source and
destination here are from the perspective of the packet receiver — typically the source is a
virtual server-side address and the destination is the client's inner tunnel address:
{
"Messages": [
{
"Data": "AQIDBA==",
"Remote": {
"Address": "203.0.113.42",
"Port": 51820,
"PeerKey": "base64encodedWireGuardPublicKey=="
},
"Inner": {
"SourceAddress": "10.0.0.1",
"SourcePort": 53,
"DestinationAddress": "10.0.0.2",
"DestinationPort": 12345
}
}
]
}
If the Inner block is absent for a DecapsulatedDelivery Listener, the packet is
dropped. For WireGuard Listeners without DecapsulatedDelivery, the Inner block is
ignored.
Proxylity maintains delivery queues per supported AWS region. Each message published to your SNS
topic must include an EgressRegion SNS message attribute identifying which regional
queue should receive it. Without this attribute, the message does not match any subscription's filter
policy and is silently discarded — no packet is delivered.
Set EgressRegion to the AWS region where you want the packet to exit the Proxylity
network. For replies to inbound packets, use the ingress region from the original packet JSON
envelope (IngressRegion field) — this ensures the packet egresses from the same region
the client's traffic entered.
For proactive pushes that are not replies to a specific inbound packet, choose the region closest to your target clients.
# Python: always include EgressRegion as a message attribute
sns.publish(
TopicArn=REPLY_TOPIC_ARN,
MessageAttributes={
"EgressRegion": {"DataType": "String", "StringValue": ingress_region}
},
Message=json.dumps({ "Messages": [ ... ] })
)
A single SNS publish can carry multiple packets by including more than one entry in the
Messages array. Each entry is processed and delivered independently:
{
"Messages": [
{
"Data": "AQIDBA==",
"Remote": { "Address": "203.0.113.1", "Port": 4567 }
},
{
"Data": "BQYHCA==",
"Remote": { "Address": "203.0.113.2", "Port": 4567 }
}
]
}
This is useful for fan-out scenarios where a single event needs to reach many clients. SNS delivery costs are per-publish, so batching reduces SNS charges while Proxylity billing remains per-packet.
The Packet Source resource subscribes to your SNS topic during creation using the role you provide.
The IAM policy granting those subscription permissions must exist before CloudFormation creates the
Packet Source. Use a DependsOn attribute to enforce this ordering:
ConfirmSource:
DependsOn:
- ProxylitySubscribeToTopicPolicy
Type: Custom::ProxylityUdpGatewayPacketSource
Properties:
...
Without DependsOn, CloudFormation may attempt to create the Packet Source before the
policy is attached to the role, causing the subscription call to fail with an access-denied error.
Proxylity requires an IAM role in your account to subscribe its SQS delivery queues to your SNS topic. The role must allow Proxylity's AWS account to assume it, and its policy must grant these permissions on the topic resource:
sns:Subscribe — to register Proxylity's delivery queues as subscriberssns:Unsubscribe — to remove subscriptions when the Packet Source is deleted or updatedsns:ListSubscriptionsByTopic — to enumerate existing subscriptions during updatesExample IAM policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sns:Subscribe",
"sns:Unsubscribe",
"sns:ListSubscriptionsByTopic"
],
"Resource": "arn:aws:sns:us-east-1:123456789012:my-packet-source-topic"
}
]
}
See Connect Your AWS Account for guidance on the role trust relationship required for Proxylity to assume roles in your account.
Packet Sources follow UDP semantics: delivery is best-effort. If Proxylity cannot deliver a packet — because
the client is unreachable, the Remote object is malformed, or the peer session has expired — the
packet is silently discarded, consistent with UDP's connectionless nature.
Two mechanisms help you observe and respond to delivery failures:
Packet Sources are managed through Infrastructure as Code using
Custom::ProxylityUdpGatewayPacketSource CloudFormation resources. For the full property
reference, syntax examples, and message format specification, see the
PacketSource CloudFormation Reference.