1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
| | // SPDX-License-Identifier: GPL-2.0-or-later
/* PASST - Plug A Simple Socket Transport
* for qemu/UNIX domain socket mode
*
* PASTA - Pack A Subtle Tap Abstraction
* for network namespace/tap device mode
*
* PESTO - Programmable Extensible Socket Translation Orchestrator
* front-end for passt(1) and pasta(1) forwarding configuration
*
* fwd_rule.c - Helpers for working with forwarding rule specifications
*
* Copyright Red Hat
* Author: David Gibson <david@gibson.dropbear.id.au>
*/
#include <stdio.h>
#include "fwd_rule.h"
/**
* fwd_rule_addr() - Return match address for a rule
* @rule: Forwarding rule
*
* Return: matching address for rule, NULL if it matches all addresses
*/
const union inany_addr *fwd_rule_addr(const struct fwd_rule *rule)
{
if (rule->flags & FWD_DUAL_STACK_ANY)
return NULL;
return &rule->addr;
}
/**
* fwd_rule_fmt() - Prettily format forwarding rule as a string
* @rule: Rule to format
* @dst: Buffer to store output (should have FWD_RULE_STRLEN bytes)
* @size: Size of @dst
*/
static const char *fwd_rule_fmt(const struct fwd_rule *rule,
char *dst, size_t size)
{
const char *percent = *rule->ifname ? "%" : "";
const char *weak = "", *scan = "";
char addr[INANY_ADDRSTRLEN];
int len;
inany_ntop(fwd_rule_addr(rule), addr, sizeof(addr));
if (rule->flags & FWD_WEAK)
weak = " (best effort)";
if (rule->flags & FWD_SCAN)
scan = " (auto-scan)";
if (rule->first == rule->last) {
len = snprintf(dst, size,
"%s [%s]%s%s:%hu => %hu %s%s",
ipproto_name(rule->proto), addr, percent,
rule->ifname, rule->first, rule->to, weak, scan);
} else {
in_port_t tolast = rule->last - rule->first + rule->to;
len = snprintf(dst, size,
"%s [%s]%s%s:%hu-%hu => %hu-%hu %s%s",
ipproto_name(rule->proto), addr, percent,
rule->ifname, rule->first, rule->last,
rule->to, tolast, weak, scan);
}
if (len < 0 || (size_t)len >= size)
return NULL;
return dst;
}
/**
* fwd_rules_info() - Print forwarding rules for debugging
* @fwd: Table to print
*/
void fwd_rules_info(const struct fwd_rule *rules, size_t count)
{
unsigned i;
for (i = 0; i < count; i++) {
char buf[FWD_RULE_STRLEN];
info(" %s", fwd_rule_fmt(&rules[i], buf, sizeof(buf)));
}
}
/**
* fwd_rule_conflicts() - Test if two rules conflict with each other
* @a, @b: Rules to test
*/
static bool fwd_rule_conflicts(const struct fwd_rule *a, const struct fwd_rule *b)
{
if (a->proto != b->proto)
/* Non-conflicting protocols */
return false;
if (!inany_matches(fwd_rule_addr(a), fwd_rule_addr(b)))
/* Non-conflicting addresses */
return false;
assert(a->first <= a->last && b->first <= b->last);
if (a->last < b->first || b->last < a->first)
/* Port ranges don't overlap */
return false;
return true;
}
/* fwd_rule_conflict_check() - Die with errir if rule conflicts with any in list
* @new: New rule
* @rules: Existing rules against which to test
* @count: Number of rules in @rules
*/
void fwd_rule_conflict_check(const struct fwd_rule *new,
const struct fwd_rule *rules, size_t count)
{
unsigned i;
for (i = 0; i < count; i++) {
char newstr[FWD_RULE_STRLEN], rulestr[FWD_RULE_STRLEN];
if (!fwd_rule_conflicts(new, &rules[i]))
continue;
die("Forwarding configuration conflict: %s versus %s",
fwd_rule_fmt(new, newstr, sizeof(newstr)),
fwd_rule_fmt(&rules[i], rulestr, sizeof(rulestr)));
}
}
|