Commit Graph

7 Commits

Author SHA1 Message Date
Ben Roberts
d54573e469 Implement BGP MD5 Auth
BGP peers can now be secured with MD5 authentication (TCP MD5 signatures as defined in RFC 2385). This provides an additional layer of security to prevent unauthorized BGP sessions.

MD5 authentication is configured per peer and supports two methods for specifying passwords:

Store passwords in environment variables for better security:

```yaml
bgp:
  local_as: 12345
  peers:
    - peer_ip: 10.10.10.1
      peer_as: 6789
      md5_env_var: GOCAST_BGP_PEER1_PASSWORD
```

Set the environment variable before starting gocast:

```bash
export GOCAST_BGP_PEER1_PASSWORD="your_secret_password"
./gocast -config config.yaml
```

**Benefits:**
- Passwords not stored in config files
- Easier secret rotation
- Better for containerized deployments (Kubernetes secrets, Docker secrets, etc.)
- Compatible with secret management systems (Vault, AWS Secrets Manager, etc.)

Specify passwords directly in the config file:

```yaml
bgp:
  local_as: 12345
  peers:
    - peer_ip: 10.10.10.1
      peer_as: 6789
      md5_password: "your_secret_password"
```

**Note:** This method is less secure as passwords are stored in plain text. Only use for testing or when environment variables are not available.

When both `md5_env_var` and `md5_password` are specified, the environment variable takes priority. This allows you to:
- Define a default password in the config
- Override it with an environment variable in production
- Use different passwords per environment without changing config files

Different peers can use different authentication methods:

```yaml
bgp:
  local_as: 12345
  peers:
    # Peer 1: Environment variable
    - peer_ip: 10.10.10.1
      peer_as: 6789
      md5_env_var: GOCAST_BGP_PEER1_PASSWORD

    # Peer 2: Config file password
    - peer_ip: 10.10.10.2
      peer_as: 6789
      md5_password: "fallback_password"

    # Peer 3: No authentication
    - peer_ip: 10.10.10.3
      peer_as: 6789
```

Recommended naming patterns:

```bash
export GOCAST_BGP_PRIMARY_PEER_PASSWORD="secret1"
export GOCAST_BGP_SECONDARY_PEER_PASSWORD="secret2"

export GOCAST_BGP_10_10_10_1_PASSWORD="secret1"
export GOCAST_BGP_10_10_10_2_PASSWORD="secret2"

export GOCAST_BGP_AS6789_PASSWORD="secret1"
```

**config/config.go**
- Added `MD5Password` field to `PeerConfig` for config file passwords
- Added `MD5EnvVar` field to `PeerConfig` for environment variable references

**controller/bgp.go**
- Added `getMD5Password()` helper function to retrieve passwords
- Modified `addPeer()` to configure MD5 authentication when available
- Environment variable lookup prioritizes env vars over config passwords

Comprehensive test suite covering:
- MD5 password from config file
- MD5 password from environment variable
- Environment variable priority over config
- No authentication scenario
- Fallback to config when env var is empty
- Multiple peers with mixed authentication methods

This commit was written using AI LLM

Authored-By: Claude Code (Sonnet 4.5)
2026-06-17 15:52:43 +01:00
Ben Roberts
567a84095e Implement support for multiple BGP peers
The BGP controller now supports announcing routes to multiple BGP peers for redundancy and resilience. If one peer fails, route announcements continue to succeed for other healthy peers.

```yaml
bgp:
  local_as: 12345
  local_ip: 192.168.1.100  # optional
  peers:
    - peer_ip: 10.10.10.1
      peer_as: 6789
      communities:        # per-peer communities (optional)
        - 100:100
    - peer_ip: 10.10.10.2
      peer_as: 6789
      communities:
        - 100:101
      multi_hop: true     # optional, defaults to true for eBGP
  communities:            # global communities applied to all peers
    - 1000:1000
  origin: igp
```

```yaml
bgp:
  local_as: 12345
  peer_as: 6789
  peer_ip: 10.10.10.1
  communities:
    - 100:100
  origin: igp
```

Legacy configurations are automatically converted to the new format internally, ensuring backward compatibility.

Routes are announced to all configured peers. If announcement to one peer fails, the operation continues for other peers. Errors are aggregated and returned, but partial success is allowed.

Communities are merged in the following order:
1. **Global communities** (defined at `bgp.communities`)
2. **Per-peer communities** (defined at `bgp.peers[].communities`)
3. **Per-route communities** (defined at `apps[].vip_config.bgp_communities`)

Example: If global communities are `[1000:1000]`, peer communities are `[100:100]`, and route communities are `[5000:5000]`, the announced route will have all three: `[1000:1000, 100:100, 5000:5000]`.

- **Default behavior**: Multi-hop is disabled by default
- **Enable**: Set `multi_hop: true` per peer to explicitly enable multi-hop BGP

The `/info` endpoint now returns an array of peer information instead of a single peer object:

**Before:**
```json
{
  "conf": {
    "neighbor_address": "10.10.10.1",
    "peer_as": 6789
  },
  "state": {...}
}
```

**After:**
```json
[
  {
    "conf": {
      "neighbor_address": "10.10.10.1",
      "peer_as": 6789
    },
    "state": {...}
  },
  {
    "conf": {
      "neighbor_address": "10.10.10.2",
      "peer_as": 6789
    },
    "state": {...}
  }
]
```

- `config/config.go`: Added `PeerConfig` struct and `Peers` slice to `BgpConfig`
- `controller/bgp.go`: Refactored to support multiple peers with best-effort semantics
- `controller/monitor.go`: Updated `GetInfo()` to return slice of peers
- `server/server.go`: Updated info handler to return array of peers

1. **Controller struct** now stores `[]PeerConfig` instead of single peer fields
2. **Announce/Withdraw** methods loop through all peers with error aggregation
3. **getApiPath** accepts a `PeerConfig` parameter for per-peer community merging
4. **addPeer** determines multi-hop settings per peer
5. **PeerInfo** returns information for all configured peers
6. **Shutdown** gracefully shuts down all peer sessions

The implementation includes comprehensive test coverage:

1. **TestLegacyConfigConversion** - Verifies backward compatibility by testing that legacy single-peer configs are automatically converted to multi-peer format
2. **TestMultiPeerConfig** - Tests that new multi-peer configurations are properly loaded with multiple peers
3. **TestNoPeersConfigError** - Ensures proper error handling when no peers are configured
4. **TestCommunityMerging** - Validates that global, per-peer, and per-route communities are correctly merged in order
5. **TestMultiHopConfiguration** - Tests multi-hop BGP settings with various scenarios:
   - Default behavior (multi-hop disabled)
   - Explicit multi-hop disable
   - Explicit multi-hop enable
6. **TestBestEffortAnnouncement** - Verifies that announcements succeed even when individual peers may have issues
7. **TestWithdrawMultiplePeers** - Tests route withdrawal across multiple peers
8. **TestPeerInfoMultiplePeers** - Validates that peer information is correctly returned for all configured peers

- **TestBgpNew** - Full integration test with actual BGP listeners (requires root, skipped in CI)
- **TestMultiPeerAnnouncement** - Tests actual route announcements to multiple BGP listeners (requires root, skipped in CI)

Existing configurations using `peer_ip` and `peer_as` continue to work without modification.

To add a second peer for resilience:

```yaml
bgp:
  local_as: 12345
  # Keep existing config for backward compatibility, or remove these lines
  # peer_as: 6789
  # peer_ip: 10.10.10.1

  # Add new multi-peer config
  peers:
    - peer_ip: 10.10.10.1
      peer_as: 6789
    - peer_ip: 10.10.10.2  # redundant peer
      peer_as: 6789
  communities:
    - 100:100
  origin: igp
```

All operations (Announce, Withdraw, Shutdown) use best-effort error handling:
- Operations continue even if individual peers fail
- Errors are collected and returned as aggregated error messages
- Format: `"announcement errors: [peer 10.10.10.1: error message, peer 10.10.10.2: error message]"`

These changes were authored via AI LLM.

Authored-By: Claude Code (Sonnet 4.5)
2026-06-17 15:52:43 +01:00
Mayuresh Gaitonde
5821c01a7b Add ability to specify vip parameters 2021-05-13 20:33:05 -07:00
Mayuresh Gaitonde
6be4d69d02 Add unit tests 2020-12-17 17:25:53 -08:00
Mayuresh Gaitonde
e15172111e fix non local peer and add multihop 2018-11-26 16:44:39 -08:00
Mayuresh Gaitonde
6fafdbbd16 ADd consul support , multiple monitors, config file 2018-10-25 22:23:04 -07:00
Mayuresh Gaitonde
e20f691de5 Initial commit for gocast 2018-10-22 19:03:42 -07:00