From 630452c56a2fd302aeddc28707fe9caa050d24d1 Mon Sep 17 00:00:00 2001 From: Chris Linton-Ford Date: Mon, 30 Sep 2024 11:39:52 +0100 Subject: [PATCH 1/8] Extend PCAP FCS detection * Return `nothing` when detection was inconclusive * Keep checking packets until conclusion is reached, or EOF is reached * Optionally compare computed FCS for extra certainty (on by default) --- src/fcs.jl | 32 +++++++++++++++--------- test/fcs_tests.jl | 63 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/fcs.jl b/src/fcs.jl index 860a833..f2a6ce4 100644 --- a/src/fcs.jl +++ b/src/fcs.jl @@ -8,12 +8,17 @@ const ETHERTYPE_IPV4 = UInt16(0x0800) const IP_TOTAL_LENGTH_OFFSET = ETHERNET_HEADER_SIZE + 2 """ - pcap_has_fcs(::PcapReader) + pcap_has_fcs(::PcapReader; confirm_checksum = true) -> Union{Nothing, Bool} Heuristically determine whether captured frames contain Ethernet FCS or not. Unfortunately, PCAP format doesn't provide this information explicitly. + +If it is not possible to determine the status, return `nothing`. + +By default, potential FCS frames have their checksum recomputed as additional +confirmation: disable this with `confirm_checksum = false`. """ -function pcap_has_fcs(reader::PcapReader) +function pcap_has_fcs(reader::PcapReader; confirm_checksum=true) mark(reader) try while !eof(reader) @@ -31,19 +36,22 @@ function pcap_has_fcs(reader::PcapReader) ip_total_length = GC.@preserve record unsafe_load(convert(Ptr{UInt16}, frame + IP_TOTAL_LENGTH_OFFSET)) ip_total_length = ntoh(ip_total_length) if ip_total_length + ETHERNET_HEADER_SIZE + ETHERNET_FCS_LENGTH == hdr.orig_len - return true + if confirm_checksum + if check_fcs(record) + return true + else + # Could be a corrupt frame, keep looking + continue + end + else + return true + end elseif ip_total_length + ETHERNET_HEADER_SIZE == hdr.orig_len return false end end - # if we couldn't read single IP packet, it doesn't really matter what to return - return false - catch e - if e isa EOFError - return false - else - rethrow() - end + # Couldn't find any packets useful for FCS detection + return nothing finally reset(reader) end @@ -55,7 +63,7 @@ end Recompute the FCS for a record. """ function compute_fcs(x::PcapRecord) - data_no_fcs = UnsafeArray{UInt8, 1}(x.data.pointer, x.data.size .- ETHERNET_FCS_LENGTH) + data_no_fcs = UnsafeArray{UInt8,1}(x.data.pointer, x.data.size .- ETHERNET_FCS_LENGTH) GC.@preserve x CRC32.unsafe_crc32(data_no_fcs, length(data_no_fcs) % Csize_t, 0x00000000) end diff --git a/test/fcs_tests.jl b/test/fcs_tests.jl index d6d928c..b478b78 100644 --- a/test/fcs_tests.jl +++ b/test/fcs_tests.jl @@ -1,29 +1,66 @@ -const PCAP_FCS = base64decode(""" -1MOyoQIABAAAAAAAAAAAAABAAAABAAAATHLDZMwhDABeAAAAXgAAAAEAXgByrQDXj6hWAQgARQAA +const PCAP_FILE_HEADER = "TTyyoQIABAAAAAAAAAAAAAAGAAABAAAA" + +const PCAP_FCS = """ +THLDZMwhDABeAAAAXgAAAAEAXgByrQDXj6hWAQgARQAA TGk3QAD9Eag2wR1YZ+AAcq1KeuaZADhwtSAAyDL/////HxIFAHRgAwAMAQAAAAAAAAzrS61s+HUX EADJMv////9OAAAAAAAAALygjcY= -""") +""" -const PCAP_NOFCS = base64decode(""" -1MOyoQIABAAAAAAAAAAAAAAABAABAAAAablkZZ4hAgBiAAAAYgAAAAABIQIgTBjATYjFhQgARQAA +const PCAP_NOFCS = """ +ablkZZ4hAgBiAAAAYgAAAAABIQIgTBjATYjFhQgARQAA VMmzQABAAVv6CksAZQpLAAEIANTpAAIAAWm5ZGUAAAAAlCECAAAAAAAQERITFBUWFxgZGhscHR4f ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 -""") +""" -const PCAP_CORRUPT_FCS = base64decode(""" -1MOyoQIABAAAAAAAAAAAAABAAAABAAAATHLDZMwhDABeAAAAXgAAAAEAXgByrQDXj6hWAQgARQAA +const PCAP_CORRUPT_FCS = """ +THLDZMwhDABeAAAAXgAAAAEAXgByrQDXj6hWAQgARQAA TGk3QAD9Eag2wR1YZ+AAcq1KeuaZADhwtSAAyDL/////HxIFAHRgAwAMAQAAAAAAAAzrS61s+HUX EADJMv////9OAAAAAAAAALygjcg= -""") +""" + +# Miniumum ethernet packet size (60 bytes without FCS) +const PCAP_SMALL = """ +Tq98Zs+xVzM8AAAAPAAAAAEAXgBynQDXj6hFQQgARQAA +HrAOQAD9EV7swR1bGOAAcp3yuObOAAr2hcD4AAAAAAAAAAAAAAAAAAAAAA== +""" + +# Non-IPv4 packet (ARP protocol) +const PCAP_NONIP = """ +8+/iZolNFC1AAAAAQAAAAAD2Y0DDvGQ/XwHjQwgGAAEI +AAYEAAFkP18B40Na4gKMAAAAAAAAWuICgQAAAAAAAAAAAAAAAAAAAAAAAOr6Tyw= +""" + +check_has_fcs(packets; confirm_checksum=true) = + pushfirst!(packets, PCAP_FILE_HEADER) |> + join |> + base64decode |> + PcapBufferReader |> + (x -> pcap_has_fcs(x; confirm_checksum)) @testset "pcap_has_fcs" begin - @test pcap_has_fcs(PcapBufferReader(PCAP_FCS)) - @test !pcap_has_fcs(PcapBufferReader(PCAP_NOFCS)) + @test check_has_fcs([PCAP_FCS]) + @test !check_has_fcs([PCAP_NOFCS]) + + @test isnothing(check_has_fcs([PCAP_NONIP])) + @test isnothing(check_has_fcs([PCAP_SMALL])) + @test isnothing(check_has_fcs([""])) # empty pcap + + @test check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_FCS]) + @test !check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_NOFCS]) + + # Corrupt FCS packets will be ignored by default + @test isnothing(check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS])) + # But corrupt FCS can be explicitly allowed + @test check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]; confirm_checksum=false) + + # Make sure we skip corrupt frames if confirm_checksum is on + @test check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_FCS]) + @test !check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_NOFCS]) end @testset "compute_fcs" begin - r_fcs = read(PcapBufferReader(PCAP_FCS)) + r_fcs = read(PcapBufferReader(base64decode(PCAP_FILE_HEADER * PCAP_FCS))) @test check_fcs(r_fcs) - r_no_fcs = read(PcapBufferReader(PCAP_CORRUPT_FCS)) + r_no_fcs = read(PcapBufferReader(base64decode(PCAP_FILE_HEADER * PCAP_CORRUPT_FCS))) @test !check_fcs(r_no_fcs) end From ac09bcb9610291f9fb233a4f9e59a42d34c4e60f Mon Sep 17 00:00:00 2001 From: Chris Linton-Ford Date: Mon, 30 Sep 2024 11:44:32 +0100 Subject: [PATCH 2/8] Bump version to 1.5.0 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c841432..9fc4112 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PcapTools" uuid = "222fe7e8-3f39-464a-bf97-d9bbb753f246" authors = ["Christian Rorvik "] -version = "1.4.0" +version = "1.5.0" [deps] CRC32 = "b4567568-9dcc-467e-9b62-c342d3a501d3" From a6b02f5a52faf540281b029f5e090ea64eac1c01 Mon Sep 17 00:00:00 2001 From: klf-gs Date: Mon, 30 Sep 2024 12:00:50 +0100 Subject: [PATCH 3/8] Add type in docstring Co-authored-by: Christian Rorvik --- src/fcs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fcs.jl b/src/fcs.jl index f2a6ce4..a5f044f 100644 --- a/src/fcs.jl +++ b/src/fcs.jl @@ -18,7 +18,7 @@ If it is not possible to determine the status, return `nothing`. By default, potential FCS frames have their checksum recomputed as additional confirmation: disable this with `confirm_checksum = false`. """ -function pcap_has_fcs(reader::PcapReader; confirm_checksum=true) +function pcap_has_fcs(reader::PcapReader; confirm_checksum::Bool = true) mark(reader) try while !eof(reader) From e81c931e4f19a704b0b94aab5fa26b2af768e115 Mon Sep 17 00:00:00 2001 From: klf-gs Date: Mon, 30 Sep 2024 12:02:36 +0100 Subject: [PATCH 4/8] Undo autoformat Co-authored-by: Christian Rorvik --- src/fcs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fcs.jl b/src/fcs.jl index a5f044f..042d20b 100644 --- a/src/fcs.jl +++ b/src/fcs.jl @@ -63,7 +63,7 @@ end Recompute the FCS for a record. """ function compute_fcs(x::PcapRecord) - data_no_fcs = UnsafeArray{UInt8,1}(x.data.pointer, x.data.size .- ETHERNET_FCS_LENGTH) + data_no_fcs = UnsafeArray{UInt8, 1}(x.data.pointer, x.data.size .- ETHERNET_FCS_LENGTH) GC.@preserve x CRC32.unsafe_crc32(data_no_fcs, length(data_no_fcs) % Csize_t, 0x00000000) end From f72db06f08a810322b12fdcaf29badef111a8e1e Mon Sep 17 00:00:00 2001 From: klf-gs Date: Mon, 30 Sep 2024 12:05:39 +0100 Subject: [PATCH 5/8] More concise conditionals Co-authored-by: Sergey Fokin --- src/fcs.jl | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/fcs.jl b/src/fcs.jl index 042d20b..9460e44 100644 --- a/src/fcs.jl +++ b/src/fcs.jl @@ -36,14 +36,7 @@ function pcap_has_fcs(reader::PcapReader; confirm_checksum::Bool = true) ip_total_length = GC.@preserve record unsafe_load(convert(Ptr{UInt16}, frame + IP_TOTAL_LENGTH_OFFSET)) ip_total_length = ntoh(ip_total_length) if ip_total_length + ETHERNET_HEADER_SIZE + ETHERNET_FCS_LENGTH == hdr.orig_len - if confirm_checksum - if check_fcs(record) - return true - else - # Could be a corrupt frame, keep looking - continue - end - else + if !confirm_checksum || check_fcs(record) return true end elseif ip_total_length + ETHERNET_HEADER_SIZE == hdr.orig_len From b6b47e14e4a7a29d35795d1fcc60c8b85f6488d8 Mon Sep 17 00:00:00 2001 From: Chris Linton-Ford Date: Mon, 30 Sep 2024 14:38:59 +0100 Subject: [PATCH 6/8] Separate ternary and boolean functions --- src/PcapTools.jl | 1 + src/fcs.jl | 22 ++++++++++++++-------- test/fcs_tests.jl | 28 +++++++++++++++------------- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/PcapTools.jl b/src/PcapTools.jl index a3e365a..a38bcd3 100644 --- a/src/PcapTools.jl +++ b/src/PcapTools.jl @@ -13,6 +13,7 @@ export PcapWriter, PcapStreamWriter export LINKTYPE_NULL, LINKTYPE_ETHERNET export splitcap export pcap_has_fcs, check_fcs, compute_fcs, ETHERNET_FCS_LENGTH +export FcsPresent, FcsAbsent, FcsUndetermined, try_detect_fcs abstract type PcapReader end abstract type PcapWriter end diff --git a/src/fcs.jl b/src/fcs.jl index 9460e44..00718c4 100644 --- a/src/fcs.jl +++ b/src/fcs.jl @@ -7,18 +7,18 @@ const ETHERNET_ETHERTYPE_OFFSET = 12 const ETHERTYPE_IPV4 = UInt16(0x0800) const IP_TOTAL_LENGTH_OFFSET = ETHERNET_HEADER_SIZE + 2 +@enum FcsStatus FcsPresent FcsAbsent FcsUndetermined + """ - pcap_has_fcs(::PcapReader; confirm_checksum = true) -> Union{Nothing, Bool} + try_detect_fcs(::PcapReader; confirm_checksum = true) -> FcsStatus Heuristically determine whether captured frames contain Ethernet FCS or not. Unfortunately, PCAP format doesn't provide this information explicitly. -If it is not possible to determine the status, return `nothing`. - By default, potential FCS frames have their checksum recomputed as additional confirmation: disable this with `confirm_checksum = false`. """ -function pcap_has_fcs(reader::PcapReader; confirm_checksum::Bool = true) +function try_detect_fcs(reader::PcapReader; confirm_checksum::Bool = true) mark(reader) try while !eof(reader) @@ -37,19 +37,25 @@ function pcap_has_fcs(reader::PcapReader; confirm_checksum::Bool = true) ip_total_length = ntoh(ip_total_length) if ip_total_length + ETHERNET_HEADER_SIZE + ETHERNET_FCS_LENGTH == hdr.orig_len if !confirm_checksum || check_fcs(record) - return true + return FcsPresent end elseif ip_total_length + ETHERNET_HEADER_SIZE == hdr.orig_len - return false + return FcsAbsent end end - # Couldn't find any packets useful for FCS detection - return nothing + return FcsUndetermined finally reset(reader) end end + +""" + pcap_has_fcs(::PcapReader; confirm_checksum = true) -> Union{Nothing, Bool} +""" +pcap_has_fcs(reader::PcapReader; confirm_checksum=true) = try_detect_fcs(reader; confirm_checksum) == FcsPresent + + """ compute_fcs(x::PcapRecord) -> UInt32 diff --git a/test/fcs_tests.jl b/test/fcs_tests.jl index b478b78..c836b7b 100644 --- a/test/fcs_tests.jl +++ b/test/fcs_tests.jl @@ -30,32 +30,34 @@ const PCAP_NONIP = """ AAYEAAFkP18B40Na4gKMAAAAAAAAWuICgQAAAAAAAAAAAAAAAAAAAAAAAOr6Tyw= """ -check_has_fcs(packets; confirm_checksum=true) = +check_detect_fcs(packets; confirm_checksum=true) = pushfirst!(packets, PCAP_FILE_HEADER) |> join |> base64decode |> PcapBufferReader |> - (x -> pcap_has_fcs(x; confirm_checksum)) + (x -> try_detect_fcs(x; confirm_checksum)) @testset "pcap_has_fcs" begin - @test check_has_fcs([PCAP_FCS]) - @test !check_has_fcs([PCAP_NOFCS]) + @test pcap_has_fcs(PcapBufferReader(base64decode(PCAP_FILE_HEADER * PCAP_FCS))) + @test !pcap_has_fcs(PcapBufferReader(base64decode(PCAP_FILE_HEADER * PCAP_NOFCS))) +end - @test isnothing(check_has_fcs([PCAP_NONIP])) - @test isnothing(check_has_fcs([PCAP_SMALL])) - @test isnothing(check_has_fcs([""])) # empty pcap +@testset "try_detect_fcs" begin + @test check_detect_fcs([PCAP_NONIP]) == FcsUndetermined + @test check_detect_fcs([PCAP_SMALL]) == FcsUndetermined + @test check_detect_fcs([""]) == FcsUndetermined # empty pcap - @test check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_FCS]) - @test !check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_NOFCS]) + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_FCS]) == FcsPresent + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_NOFCS]) == FcsAbsent # Corrupt FCS packets will be ignored by default - @test isnothing(check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS])) + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]) == FcsUndetermined # But corrupt FCS can be explicitly allowed - @test check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]; confirm_checksum=false) + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]; confirm_checksum=false) == FcsPresent # Make sure we skip corrupt frames if confirm_checksum is on - @test check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_FCS]) - @test !check_has_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_NOFCS]) + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_FCS]) == FcsPresent + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_NOFCS]) == FcsAbsent end @testset "compute_fcs" begin From bcd2749cfbfe7fe9bd42291c5968c8226d6267ac Mon Sep 17 00:00:00 2001 From: klf-gs Date: Mon, 30 Sep 2024 16:12:19 +0100 Subject: [PATCH 7/8] Apply suggestions from code review Consistency Co-authored-by: Christian Rorvik --- src/PcapTools.jl | 5 +++-- src/fcs.jl | 10 +++++----- test/fcs_tests.jl | 18 +++++++++--------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/PcapTools.jl b/src/PcapTools.jl index a38bcd3..df132a4 100644 --- a/src/PcapTools.jl +++ b/src/PcapTools.jl @@ -11,9 +11,10 @@ export PcapRecord export PcapReader, PcapStreamReader, PcapBufferReader export PcapWriter, PcapStreamWriter export LINKTYPE_NULL, LINKTYPE_ETHERNET +export ETHERNET_FCS_LENGTH +export FCSPresence, FCS_PRESENT, FCS_ABSENT, FCS_UNDETERMINED export splitcap -export pcap_has_fcs, check_fcs, compute_fcs, ETHERNET_FCS_LENGTH -export FcsPresent, FcsAbsent, FcsUndetermined, try_detect_fcs +export try_detect_fcs, pcap_has_fcs, check_fcs, compute_fcs abstract type PcapReader end abstract type PcapWriter end diff --git a/src/fcs.jl b/src/fcs.jl index 00718c4..199a059 100644 --- a/src/fcs.jl +++ b/src/fcs.jl @@ -7,7 +7,7 @@ const ETHERNET_ETHERTYPE_OFFSET = 12 const ETHERTYPE_IPV4 = UInt16(0x0800) const IP_TOTAL_LENGTH_OFFSET = ETHERNET_HEADER_SIZE + 2 -@enum FcsStatus FcsPresent FcsAbsent FcsUndetermined +@enum FCSPresence FCS_PRESENT FCS_ABSENT FCS_UNDETERMINED """ try_detect_fcs(::PcapReader; confirm_checksum = true) -> FcsStatus @@ -37,13 +37,13 @@ function try_detect_fcs(reader::PcapReader; confirm_checksum::Bool = true) ip_total_length = ntoh(ip_total_length) if ip_total_length + ETHERNET_HEADER_SIZE + ETHERNET_FCS_LENGTH == hdr.orig_len if !confirm_checksum || check_fcs(record) - return FcsPresent + return FCS_PRESENT end elseif ip_total_length + ETHERNET_HEADER_SIZE == hdr.orig_len - return FcsAbsent + return FCS_ABSENT end end - return FcsUndetermined + return FCS_UNDETERMINED finally reset(reader) end @@ -53,7 +53,7 @@ end """ pcap_has_fcs(::PcapReader; confirm_checksum = true) -> Union{Nothing, Bool} """ -pcap_has_fcs(reader::PcapReader; confirm_checksum=true) = try_detect_fcs(reader; confirm_checksum) == FcsPresent +pcap_has_fcs(reader::PcapReader; kwargs...) = try_detect_fcs(reader; kwargs...) == FCS_PRESENT """ diff --git a/test/fcs_tests.jl b/test/fcs_tests.jl index c836b7b..1561e09 100644 --- a/test/fcs_tests.jl +++ b/test/fcs_tests.jl @@ -43,21 +43,21 @@ check_detect_fcs(packets; confirm_checksum=true) = end @testset "try_detect_fcs" begin - @test check_detect_fcs([PCAP_NONIP]) == FcsUndetermined - @test check_detect_fcs([PCAP_SMALL]) == FcsUndetermined - @test check_detect_fcs([""]) == FcsUndetermined # empty pcap + @test check_detect_fcs([PCAP_NONIP]) == FCS_UNDETERMINED + @test check_detect_fcs([PCAP_SMALL]) == FCS_UNDETERMINED + @test check_detect_fcs([""]) == FCS_UNDETERMINED # empty pcap - @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_FCS]) == FcsPresent - @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_NOFCS]) == FcsAbsent + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_FCS]) == FCS_PRESENT + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_NOFCS]) == FCS_ABSENT # Corrupt FCS packets will be ignored by default - @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]) == FcsUndetermined + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]) == FCS_UNDETERMINED # But corrupt FCS can be explicitly allowed - @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]; confirm_checksum=false) == FcsPresent + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS]; confirm_checksum = false) == FCS_PRESENT # Make sure we skip corrupt frames if confirm_checksum is on - @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_FCS]) == FcsPresent - @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_NOFCS]) == FcsAbsent + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_FCS]) == FCS_PRESENT + @test check_detect_fcs([PCAP_NONIP, PCAP_SMALL, PCAP_CORRUPT_FCS, PCAP_NOFCS]) == FCS_ABSENT end @testset "compute_fcs" begin From df7158f89c9c8951b7f79680c9f4d76925eac8e6 Mon Sep 17 00:00:00 2001 From: Chris Linton-Ford Date: Mon, 30 Sep 2024 16:30:11 +0100 Subject: [PATCH 8/8] Add back EOFError check --- src/fcs.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fcs.jl b/src/fcs.jl index 199a059..d0e69d7 100644 --- a/src/fcs.jl +++ b/src/fcs.jl @@ -44,6 +44,12 @@ function try_detect_fcs(reader::PcapReader; confirm_checksum::Bool = true) end end return FCS_UNDETERMINED + catch e + if e isa EOFError + return FCS_UNDETERMINED + else + rethrow() + end finally reset(reader) end