Skip to content

Commit 29453cb

Browse files
fix: support all allowed protocol numbers (#111528)
* fix(CommunityIdProcessor): support all allowed protocol numbers * fix(CommunityIdProcessor): update documentation
1 parent 6f53958 commit 29453cb

File tree

3 files changed

+116
-62
lines changed

3 files changed

+116
-62
lines changed

docs/reference/ingest/processors/community-id.asciidoc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ configuration is required.
2323
| `source_port` | no | `source.port` | Field containing the source port.
2424
| `destination_ip` | no | `destination.ip` | Field containing the destination IP address.
2525
| `destination_port` | no | `destination.port` | Field containing the destination port.
26-
| `iana_number` | no | `network.iana_number` | Field containing the IANA number. The following protocol numbers are currently supported: `1` ICMP, `2` IGMP, `6` TCP, `17` UDP, `47` GRE, `58` ICMP IPv6, `88` EIGRP, `89` OSPF, `103` PIM, and `132` SCTP.
26+
| `iana_number` | no | `network.iana_number` | Field containing the IANA number.
2727
| `icmp_type` | no | `icmp.type` | Field containing the ICMP type.
2828
| `icmp_code` | no | `icmp.code` | Field containing the ICMP code.
29-
| `transport` | no | `network.transport` | Field containing the transport protocol.
30-
Used only when the `iana_number` field is not present.
29+
| `transport` | no | `network.transport` | Field containing the transport protocol name or number.
30+
Used only when the `iana_number` field is not present. The following protocol names are currently supported:
31+
`ICMP`, `IGMP`, `TCP`, `UDP`, `GRE`, `ICMP IPv6`, `EIGRP`, `OSPF`, `PIM`, and `SCTP`.
3132
| `target_field` | no | `network.community_id` | Output field for the community ID.
3233
| `seed` | no | `0` | Seed for the community ID hash. Must be between
3334
0 and 65535 (inclusive). The seed can prevent hash collisions between network domains, such as

modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/CommunityIdProcessor.java

Lines changed: 85 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ private static Flow buildFlow(
225225
}
226226
flow.protocol = Transport.fromObject(protocol);
227227

228-
switch (flow.protocol) {
228+
switch (flow.protocol.getType()) {
229229
case Tcp, Udp, Sctp -> {
230230
flow.sourcePort = parseIntFromObjectOrString(sourcePort.get(), "source port");
231231
if (flow.sourcePort < 1 || flow.sourcePort > 65535) {
@@ -336,12 +336,12 @@ public CommunityIdProcessor create(
336336
*/
337337
public static final class Flow {
338338

339-
private static final List<Transport> TRANSPORTS_WITH_PORTS = List.of(
340-
Transport.Tcp,
341-
Transport.Udp,
342-
Transport.Sctp,
343-
Transport.Icmp,
344-
Transport.IcmpIpV6
339+
private static final List<Transport.Type> TRANSPORTS_WITH_PORTS = List.of(
340+
Transport.Type.Tcp,
341+
Transport.Type.Udp,
342+
Transport.Type.Sctp,
343+
Transport.Type.Icmp,
344+
Transport.Type.IcmpIpV6
345345
);
346346

347347
InetAddress source;
@@ -362,20 +362,21 @@ boolean isOrdered() {
362362
}
363363

364364
byte[] toBytes() {
365-
boolean hasPort = TRANSPORTS_WITH_PORTS.contains(protocol);
365+
Transport.Type protoType = protocol.getType();
366+
boolean hasPort = TRANSPORTS_WITH_PORTS.contains(protoType);
366367
int len = source.getAddress().length + destination.getAddress().length + 2 + (hasPort ? 4 : 0);
367368
ByteBuffer bb = ByteBuffer.allocate(len);
368369

369370
boolean isOneWay = false;
370-
if (protocol == Transport.Icmp || protocol == Transport.IcmpIpV6) {
371+
if (protoType == Transport.Type.Icmp || protoType == Transport.Type.IcmpIpV6) {
371372
// ICMP protocols populate port fields with ICMP data
372-
Integer equivalent = IcmpType.codeEquivalent(icmpType, protocol == Transport.IcmpIpV6);
373+
Integer equivalent = IcmpType.codeEquivalent(icmpType, protoType == Transport.Type.IcmpIpV6);
373374
isOneWay = equivalent == null;
374375
sourcePort = icmpType;
375376
destinationPort = equivalent == null ? icmpCode : equivalent;
376377
}
377378

378-
boolean keepOrder = isOrdered() || ((protocol == Transport.Icmp || protocol == Transport.IcmpIpV6) && isOneWay);
379+
boolean keepOrder = isOrdered() || ((protoType == Transport.Type.Icmp || protoType == Transport.Type.IcmpIpV6) && isOneWay);
379380
bb.put(keepOrder ? source.getAddress() : destination.getAddress());
380381
bb.put(keepOrder ? destination.getAddress() : source.getAddress());
381382
bb.put(toUint16(protocol.getTransportNumber() << 8));
@@ -397,68 +398,99 @@ String toCommunityId(byte[] seed) {
397398
}
398399
}
399400

400-
public enum Transport {
401-
Icmp(1),
402-
Igmp(2),
403-
Tcp(6),
404-
Udp(17),
405-
Gre(47),
406-
IcmpIpV6(58),
407-
Eigrp(88),
408-
Ospf(89),
409-
Pim(103),
410-
Sctp(132);
411-
412-
private final int transportNumber;
401+
static class Transport {
402+
public enum Type {
403+
Unknown(-1),
404+
Icmp(1),
405+
Igmp(2),
406+
Tcp(6),
407+
Udp(17),
408+
Gre(47),
409+
IcmpIpV6(58),
410+
Eigrp(88),
411+
Ospf(89),
412+
Pim(103),
413+
Sctp(132);
414+
415+
private final int transportNumber;
416+
417+
private static final Map<String, Type> TRANSPORT_NAMES;
418+
419+
static {
420+
TRANSPORT_NAMES = new HashMap<>();
421+
TRANSPORT_NAMES.put("icmp", Icmp);
422+
TRANSPORT_NAMES.put("igmp", Igmp);
423+
TRANSPORT_NAMES.put("tcp", Tcp);
424+
TRANSPORT_NAMES.put("udp", Udp);
425+
TRANSPORT_NAMES.put("gre", Gre);
426+
TRANSPORT_NAMES.put("ipv6-icmp", IcmpIpV6);
427+
TRANSPORT_NAMES.put("icmpv6", IcmpIpV6);
428+
TRANSPORT_NAMES.put("eigrp", Eigrp);
429+
TRANSPORT_NAMES.put("ospf", Ospf);
430+
TRANSPORT_NAMES.put("pim", Pim);
431+
TRANSPORT_NAMES.put("sctp", Sctp);
432+
}
413433

414-
private static final Map<String, Transport> TRANSPORT_NAMES;
434+
Type(int transportNumber) {
435+
this.transportNumber = transportNumber;
436+
}
415437

416-
static {
417-
TRANSPORT_NAMES = new HashMap<>();
418-
TRANSPORT_NAMES.put("icmp", Icmp);
419-
TRANSPORT_NAMES.put("igmp", Igmp);
420-
TRANSPORT_NAMES.put("tcp", Tcp);
421-
TRANSPORT_NAMES.put("udp", Udp);
422-
TRANSPORT_NAMES.put("gre", Gre);
423-
TRANSPORT_NAMES.put("ipv6-icmp", IcmpIpV6);
424-
TRANSPORT_NAMES.put("icmpv6", IcmpIpV6);
425-
TRANSPORT_NAMES.put("eigrp", Eigrp);
426-
TRANSPORT_NAMES.put("ospf", Ospf);
427-
TRANSPORT_NAMES.put("pim", Pim);
428-
TRANSPORT_NAMES.put("sctp", Sctp);
438+
public int getTransportNumber() {
439+
return transportNumber;
440+
}
429441
}
430442

431-
Transport(int transportNumber) {
443+
private Type type;
444+
private int transportNumber;
445+
446+
Transport(int transportNumber, Type type) { // Change constructor to public
432447
this.transportNumber = transportNumber;
448+
this.type = type;
449+
}
450+
451+
Transport(Type type) { // Change constructor to public
452+
this.transportNumber = type.getTransportNumber();
453+
this.type = type;
454+
}
455+
456+
public Type getType() {
457+
return this.type;
433458
}
434459

435460
public int getTransportNumber() {
436461
return transportNumber;
437462
}
438463

439464
public static Transport fromNumber(int transportNumber) {
440-
return switch (transportNumber) {
441-
case 1 -> Icmp;
442-
case 2 -> Igmp;
443-
case 6 -> Tcp;
444-
case 17 -> Udp;
445-
case 47 -> Gre;
446-
case 58 -> IcmpIpV6;
447-
case 88 -> Eigrp;
448-
case 89 -> Ospf;
449-
case 103 -> Pim;
450-
case 132 -> Sctp;
451-
default -> throw new IllegalArgumentException("unknown transport protocol number [" + transportNumber + "]");
465+
if (transportNumber < 0 || transportNumber >= 255) {
466+
// transport numbers range https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
467+
throw new IllegalArgumentException("invalid transport protocol number [" + transportNumber + "]");
468+
}
469+
470+
Type type = switch (transportNumber) {
471+
case 1 -> Type.Icmp;
472+
case 2 -> Type.Igmp;
473+
case 6 -> Type.Tcp;
474+
case 17 -> Type.Udp;
475+
case 47 -> Type.Gre;
476+
case 58 -> Type.IcmpIpV6;
477+
case 88 -> Type.Eigrp;
478+
case 89 -> Type.Ospf;
479+
case 103 -> Type.Pim;
480+
case 132 -> Type.Sctp;
481+
default -> Type.Unknown;
452482
};
483+
484+
return new Transport(transportNumber, type);
453485
}
454486

455487
public static Transport fromObject(Object o) {
456488
if (o instanceof Number number) {
457489
return fromNumber(number.intValue());
458490
} else if (o instanceof String protocolStr) {
459491
// check if matches protocol name
460-
if (TRANSPORT_NAMES.containsKey(protocolStr.toLowerCase(Locale.ROOT))) {
461-
return TRANSPORT_NAMES.get(protocolStr.toLowerCase(Locale.ROOT));
492+
if (Type.TRANSPORT_NAMES.containsKey(protocolStr.toLowerCase(Locale.ROOT))) {
493+
return new Transport(Type.TRANSPORT_NAMES.get(protocolStr.toLowerCase(Locale.ROOT)));
462494
}
463495

464496
// check if convertible to protocol number

modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/CommunityIdProcessorTests.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,30 @@ public void testBeatsProtocolNumber() throws Exception {
166166
testCommunityIdProcessor(event, "1:D3t8Q1aFA6Ev0A/AO4i9PnU3AeI=");
167167
}
168168

169-
public void testBeatsIanaNumber() throws Exception {
169+
public void testBeatsIanaNumberProtocolTCP() throws Exception {
170170
@SuppressWarnings("unchecked")
171171
var network = (Map<String, Object>) event.get("network");
172172
network.remove("transport");
173-
network.put("iana_number", CommunityIdProcessor.Transport.Tcp.getTransportNumber());
173+
network.put("iana_number", CommunityIdProcessor.Transport.Type.Tcp.getTransportNumber());
174174
testCommunityIdProcessor(event, "1:LQU9qZlK+B5F3KDmev6m5PMibrg=");
175175
}
176176

177+
public void testBeatsIanaNumberProtocolIPv4() throws Exception {
178+
@SuppressWarnings("unchecked")
179+
var network = (Map<String, Object>) event.get("network");
180+
network.put("iana_number", "4");
181+
network.remove("transport");
182+
@SuppressWarnings("unchecked")
183+
var source = (Map<String, Object>) event.get("source");
184+
source.put("ip", "192.168.1.2");
185+
source.remove("port");
186+
@SuppressWarnings("unchecked")
187+
var destination = (Map<String, Object>) event.get("destination");
188+
destination.put("ip", "10.1.2.3");
189+
destination.remove("port");
190+
testCommunityIdProcessor(event, "1:KXQzmk3bdsvD6UXj7dvQ4bM6Zvw=");
191+
}
192+
177193
public void testIpv6() throws Exception {
178194
@SuppressWarnings("unchecked")
179195
var source = (Map<String, Object>) event.get("source");
@@ -201,10 +217,10 @@ public void testStringAndNumber() throws Exception {
201217
@SuppressWarnings("unchecked")
202218
var network = (Map<String, Object>) event.get("network");
203219
network.remove("transport");
204-
network.put("iana_number", CommunityIdProcessor.Transport.Tcp.getTransportNumber());
220+
network.put("iana_number", CommunityIdProcessor.Transport.Type.Tcp.getTransportNumber());
205221
testCommunityIdProcessor(event, "1:LQU9qZlK+B5F3KDmev6m5PMibrg=");
206222

207-
network.put("iana_number", Integer.toString(CommunityIdProcessor.Transport.Tcp.getTransportNumber()));
223+
network.put("iana_number", Integer.toString(CommunityIdProcessor.Transport.Type.Tcp.getTransportNumber()));
208224
testCommunityIdProcessor(event, "1:LQU9qZlK+B5F3KDmev6m5PMibrg=");
209225

210226
// protocol number
@@ -359,8 +375,13 @@ private void testCommunityIdProcessor(Map<String, Object> source, int seed, Stri
359375
}
360376

361377
public void testTransportEnum() {
362-
for (CommunityIdProcessor.Transport t : CommunityIdProcessor.Transport.values()) {
363-
assertThat(CommunityIdProcessor.Transport.fromNumber(t.getTransportNumber()), equalTo(t));
378+
for (CommunityIdProcessor.Transport.Type t : CommunityIdProcessor.Transport.Type.values()) {
379+
if (t == CommunityIdProcessor.Transport.Type.Unknown) {
380+
expectThrows(IllegalArgumentException.class, () -> CommunityIdProcessor.Transport.fromNumber(t.getTransportNumber()));
381+
continue;
382+
}
383+
384+
assertThat(CommunityIdProcessor.Transport.fromNumber(t.getTransportNumber()).getType(), equalTo(t));
364385
}
365386
}
366387

0 commit comments

Comments
 (0)