Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to access IP/TCP/UDP headers #1031

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

lupino3
Copy link
Member

@lupino3 lupino3 commented Oct 30, 2019

This will allow users to access packet metadata without needing to parse
the "parsedPacket" string, and will also allow them to access the packet
data present after the headers for further computation, because the
header addresses are now exposed.

The IPHeader, TCPHeader, UDPHeader structs have been moved outside
PacketFragmentArgs to allow definition of properties with the same name.
They have been converted from structs to class to make them into
reference types and therefore have the homonymic properties return null
if the corresponding header was not successfully parsed by
ParsePacket().

I am proposing this change because I need to parse DNS request/response
in packets, and it is almost impossible to do it with the current class
structure without duplicating the code of FIndIpHeader(), and I think
that it's much cleaner to expose the headers themselves rather than just
exposing FindIpHeader() and having the users duplicate the parsing
logic.

@lupino3
Copy link
Member Author

lupino3 commented Oct 30, 2019

@brianrob could you please review? This is the last bit I need for my own ETL parsing tool which interprets DNS data. Thanks! :)

@brianrob
Copy link
Member

@lupino3 thanks for submitting. I will need a bit of time to look through this, but consider this an ack.

@lupino3
Copy link
Member Author

lupino3 commented Oct 31, 2019

Sure, thanks @brianrob. Note that the diff algorithm is fooled by my addition of two extra properties. I didn't change a lot in the body of the existing ParsedPacket getter, which is now moved to ParsePacket() to make sure it's invoked for any of the properties that need parsing.

The only changes there are storing the parsed packet, IP/TCP/UDP headers in a private class attribute, which is then returned by the corresponding property.

I also added a parsed boolean to avoid running the parsing code multiple times for no reason (the result will always be the same).

Hope the change makes sense! Thanks.

Base automatically changed from master to main February 2, 2021 23:16
@brianrob
Copy link
Member

We're working to clean-up old open PRs in this repo. This PR is greater than 1 year old. If you would like to continue working on this PR, please add a comment within the next 7 days so that we can start discussion on next steps. Otherwise, we will close this PR. Please feel free to open a new PR or issue if you'd like to re-open this discussion at a later date.

@lupino3
Copy link
Member Author

lupino3 commented Jan 15, 2025

@brianrob this is a very old PR, I haven't worked on this project for 5 years :)

That being said, I think this feature is useful and I think it should be merged.
Please let me know if there are any changes you'd need in order to get it in. Thanks!

@brianrob
Copy link
Member

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@brianrob
Copy link
Member

@lupino3 thanks for your response. I've triggered the CI for validation. Also, one additional question in the code review.

@@ -695,6 +635,119 @@ public override object PayloadValue(int index)

protected override internal void SetState(object newState) { m_state = (MicrosoftWindowsNDISPacketCaptureTraceEventParserState)newState; }
private MicrosoftWindowsNDISPacketCaptureTraceEventParserState m_state;

private bool parsed = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you expect parsed to be set to false for each new event? In most cases, you'll just have a single instance of this object and it will be attached to a raw payload and used as a parser. Thus, if you set parsed = true, it will remain true for the next event as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, I didn't take that into account at all! I see now the notice in the TraceEvent documentation. Do you think this PR looks good if I simply remove parsed, or would you recommend further changes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the idea of exposing the data is reasonable. The biggest concern I have is the lifetime. I think the way to address this would be to clone the TraceEvent object and then reference it from the networking objects rather than passing a byte*. This would ensure that the lifetime of the referenced data is correct. When you call Clone on the TraceEvent object, it copies the buffer into separate memory that will live longer than the callback. Then it's safe to do the kind of stuff that you're doing here. So, I think the right path forward would be to have an API on the event itself that gets you an intermediate object that owns a clone of the TraceEvent and then each of the structured objects that you create that take a byte* can just keep a reference to the clone. Once they all go out of scope, the clone will be finalized. Alternatively, you could keep track and dispose of the clone when done.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would copying the relevant portion of buffer into the *Header object itself make sense?

This way I don't have to manage the lifetime of TraceEvent, and the copy can be done when necessary (i.e., when the user accesses the corresponding property).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this would be fine as well.

@brianrob brianrob removed the NotStale label Jan 27, 2025
This will allow users to access packet metadata without needing to parse
the "parsedPacket" string, and will also allow them to access the packet
data present after the headers for further computation, because the
header addresses are now exposed.

The IPHeader, TCPHeader, UDPHeader structs have been moved outside
PacketFragmentArgs to allow definition of properties with the same name.
They have been converted from structs to class to make them into
reference types and therefore have the homonymic properties return null
if the corresponding header was not successfully parsed by
ParsePacket().

I am proposing this change because I need to parse DNS request/response
in packets, and it is almost impossible to do it with the current class
structure without duplicating the code of FIndIpHeader(), and I think
that it's much cleaner to expose the headers themselves rather than just
exposing FindIpHeader() and having the users duplicate the parsing
logic.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants