Features | Pricing | Documentation | Contact | Blog | About

Packet Sources

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.

When to Use Packet Sources

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.

How It Works

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:

  1. Your code publishes a message to the SNS topic containing one or more packets (destination address, port, and payload).
  2. SNS delivers the message to Proxylity's delivery infrastructure.
  3. Proxylity routes each packet through the bound Listener's egress path and sends it as a UDP datagram to the specified remote client.

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.

Using Packet Sources with Plain UDP Listeners

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.

Using Packet Sources with WireGuard Listeners

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.

PeerKey — Required for All WireGuard Listeners

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=="
      }
    }
  ]
}

Inner — Required for WireGuard Listeners with DecapsulatedDelivery

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.

Targeting an Egress Region

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": [ ... ] })
)

Batching Multiple Packets

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.

Deployment Ordering

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.

IAM Requirements

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:

Example 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.

Error Handling and Reliability

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:

Managing Packet Sources

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.