Hi Daniel - Thanks for the feedback. See my comments below . . .
On Thu, Nov 7, 2013 at 8:40 AM, Daniel Wagner <w...@monom.org> wrote: > Hi Glenn, > > [Sorry for the late response. I am kind of pretty busy] > > > On 11/05/2013 08:27 PM, Glenn Schmottlach wrote: >>>> >>>> As I understand it, Connman sessions are tracked, in part, by marking >>>> packets associated with the session's UID, GID, or SELinux context >>>> information. This is translated into iptable rules to which "mark" the >>>> connections as described in session-overview.txt. >>>> >>>> Per session iptables rules: >>>> >>>> iptables -t mangle -A OUTPUT -m owner [--uid-owner|--gid-owner] $OWNER \ >>>> -j MARK --set-mark $MARK >>>> >>>> iptables -t filter -A INPUT -m mark --mark $MARK \ >>>> -m nfacct --nfacct-name session-input-$MARK >>>> iptables -t filter -A OUTPUT -m mark --mark $MARK \ >>>> -m nfacct --nfacct-name session-output-$MARK >>> >>> >>> >>> BTW, the nfacct is going away. We are going to use NFQUEUE in future. >>> Though we still need the MARK unless we can convince the netdev >>> guys that the lookup for a policy routing table could be something else >>> e.g. cgroup id. For the time being I keep the assumption we need >>> the marker. >>> >> >> I'm curious how you anticipate using NFQUEUE in the future unless >> you're considering re-directing the network traffic to a user-space >> application (like Connman). Are you trying to do a transparent proxy >> or intercept the packets in some way? If so, have you considered >> TPROXY or even using NFLOG to get at the these packets? My only >> concern/confusion here is the intent for using NFQUEUE since it seems >> you want to funnel matching packets into user-space. Can you elaborate >> on your plans? Wouldn't this have a negative impact on the performance >> of the connections managed by Connman if you are moving in that >> direction? > > > The Session API is also designed to allow per application statistics > and routing. The current implementation is trying to use NFACCT > for the statistics. That doesn't really scale though. We need one > rule per direction and protocol type per application. Furthermore, > we need to poll for the updates. > > Android supports the same feature via xt_qtaguid. There was a good > presentation during the LPC on this topic: > > http://www.youtube.com/watch?v=Fi_iyaF7Gw0 > > Eric Dumazet and Thomas Graf were attending this session and both > said NFQUEUE is what we should use for this kind of feature we > want to support. They also pointed out that the operation is > dirt cheap. Let's see, at least we have them on tape and can > bother them to fix it if it isn't :D (just jocking). > I was not aware of this approach. I'll have to investigate this further and get back to you on whether is fits my use-case as well. Thanks for the link . . . I'll watch the video. > I and a colleague of mine already working on this. We need > to extend the connection tracking information with skuid > and skgid. We create a 'statistic daemon' to collect the data. > The main reason not add it to ConnMan directly is that > libnetfiler_queue (and friends) have a blocking API which > is completely unfit for ConnMan. Besides this I don't think > it is a great idea to have ConnMan to look at all packets. > I hope to have soon some real numbers on performance > and power impact. It sounds like an interesting approach. I would be very interested in how it turns out. Is this statistics daemon something you expect that you can share with the Connman community? > >>>> These rules instruct iptables to collect basic usage metrics >>>> (bytes/packets sent/received) on behalf of Connman. >>>> >>>> I have a requirement to do additional filtering and statistics >>>> collection using my own set of rules and would like to filter on these >>>> same MARK'ed packets while adding additional "marks" (or fields) to >>>> the packets so that I can separate them into additional categories >>>> needed by my application. This is where I need some additional >>>> information from Connman and a slight modification to how packets are >>>> MARK'ed and compared. >>>> >>>> As I understand it, each netfilter packet has an associated 32-bit >>>> mark value which is being set to $MARK in the above rules. When >>>> setting a MARK value you can provide a mask which will only allow >>>> specific bits to be set. Looking at the session.c code (line 39) I see >>>> that new sessions are initialized starting at 256 and are incremented >>>> upwards from there. So my assumption is that Connman assumes it "owns" >>>> the upper 24-bits of the netfiler mark value. Likewise, it would seem >>>> from the iptables rules that it does not expect other rules in the >>>> iptable to use these same bits for marking packets. >>> >>> >>> >>> ConnMan starts counting at 256 because that is the first 'unmanaged' >>> ID for a policy routing table. To simplify I used the same value >>> for the routing table as for the marker. Obviously the current >>> implementation doesn't really play nicely by assuming it has complete >>> control. I have no problem to change that. >>> >>> >>>> What I am proposing is the following: >>>> >>>> 1) Modify Connman to provide a mechanism to retrieve the iptable >>>> "MARK" value associated with a session as well as the bitmask used to >>>> filter/extract those bits from the underlying U32 netfilter value. >>>> Perhaps both the session MARK value and bitmask could be considered >>>> read-only "settings" of the session object and would be updated when >>>> the iptable rule is written. >>> >>> >>> >>> I don't really follow here. Could you please elaborate it a bit? >> >> >> Let me try to explain what I'm trying to accomplish. On my target >> platform there exist applications that run as separate processes. My >> intention is to run each "app" as a separate Linux user. > > > Similar to what we want to do (and Android does) > > >> These apps >> might still be further divided into groups with similar features (e.g. >> streaming apps, music apps, etc...). My thought was to assign each app >> to a Linux group, or as you indicate, perhaps a specific cgroup if I >> utilize that Linux feature. I need to enforce both a per-application >> network data quota (bytes sent + received < data limit) as well as an >> overall application "group" data limit. > > > I think we share the same use case here. Apart of the grouping of several > application I want to support the same use case That's good news. I suspect our worlds and needs are quite similar. > > >> My thought is that I could create a Connman policy (or session >> configuration) for *each* application. Connman seems to already >> provide the mechanism to provide a prioritized Bearer list and the >> necessary indications to tell an application whether the underlying >> Bearer/service is connected (or not) and to request a connection >> through the Session API. > > > Yes, the Session API is not only there for notification. > > >> It seems that when a Session is created new >> rules are added to the iptable to "mark" these packets from a >> particular application based on the UID, GID, or SELinux context. > > > Yes. > > >> I want to set up additional filters on these same marked packets >> except I also want to add a field to mark a GID association in the >> same U32 netfilter value. I need to know the netfilter mask I can use >> to mask off the fields Connman uses for each packet. My thought was to >> do this outside of Connman since it's not clear this is something >> everyone needs/desires in their architectures. > > > Maybe. Could you list your rules you want to use? Here's a smattering of rules I've been prototyping. As you can see there is nothing complex here but I suspect it's enough to give you the gist of what I'm trying to do. Right now these rules add a quota to a given UID. The GID rules would be similar but come *before* the UID quota rules since these supersede those (e.g. if it passes the GID related data limits, then apply the per UID limits). Assuming I know Connman's UID marker, I can match on the same packets for that user. CHAIN_PREFIX="chain_$UID" CHAIN_QUOTA="${CHAIN_PREFIX}_quota" ACCT="ACCT_${UID}_${MARK}" CHAIN_ACCT="${CHAIN_PREFIX}_acct" QUOTA=65536 # Create the new custom chains iptables -N $CHAIN_QUOTA iptables -N $CHAIN_ACCT # This marks all outgoing packets with a special marker per user # which will be restored when the response comes pack on the input. # We use it to track incoming packet for a specific UID. iptables -t mangle -A OUTPUT -m owner --uid-owner $UID \ -j MARK --set-mark $MARK # Hook in our custom chains iptables -t filter -A INPUT -m mark --mark $MARK -j $CHAIN_QUOTA iptables -t filter -A OUTPUT -m owner --uid-owner $UID -j $CHAIN_QUOTA iptables -t filter -A $CHAIN_QUOTA -m quota --quota $QUOTA -g $CHAIN_ACCT # Send a TCP reset for all TCP traffic iptables -t filter -A $CHAIN_QUOTA -p tcp -j REJECT --reject-with tcp-reset # Drop UDP and anything else on the floor iptables -t filter -A $CHAIN_QUOTA -j DROP iptables -t filter -A $CHAIN_ACCT -m nfacct --nfacct-name $ACCT -j RETURN > > >> Also, I want to use >> netfilter to collect metrics for a combined send/receive byte count >> since currently Connman tracks sent/received bytes separately. So in >> my solution, I add additional rules for each app (using the Connman >> "mark" value) to collect a send/receive application statistic. I also >> use my own netfilter "mark" value to track the application's Linux >> "group" so I can do group statistics and impose a quota at that level >> as well (which could override the quota at the application level). > > > This sound pretty reasonable. I don't see why something like this > should be supported upstream by ConnMan. Note we completely lack > code for supporting the quota per application so far. Yes, I'd much prefer up-streaming my changes to Connman if at all possible. Forking is always an option but I'd rather implement a n approach that can be supported from the main-line. > > >> I >> can do all of this directly with iptables (I've prototyped it by hand) >> but need Connman to provide me with the per-session/application "mark" >> value and the filter I can used to mask off that value for my own >> iptable rules. Retrieving this information as a read-only Session >> property seemed the most convenient way. I'm open to other suggestions >> however. > > > I would suggest to we join forces here and add the needed code > directly to ConnMan or the 'statistic daemon'. I think I'd be open to that. I'll have to learn more about the "statistics daemon" and it's roles/responsibilities to see how it might fit into the approach I'm considering. Can you share any of these details? > >>>> 2) Provide a configuration option (either at compile-time or via >>>> configuration file item), that specifies the offset/mask for the >>>> session's MARK value. For instance, currently the inferred offset (by >>>> examining the code) is 8 bits with 0xFFFFFFFF as the default mask. >>>> This doesn't allow the Connman markings to co-exist with any other >>>> external markings. For my application I would like to reserve the >>>> upper 16 bits for the Connman session value and the lower 16 bits for >>>> my own use. The Connman code that generates the iptables rule might be >>>> modified to look like this: >>>> >>>> iptables -t mangle -A OUTPUT -m owner [--uid-owner|--gid-owner] $OWNER \ >>>> -j MARK --set-mark $MARK/0x0000FFFF >>>> >>>> iptables -t filter -A INPUT -m mark --mark $MARK/0xFFFF0000 \ >>>> -m nfacct --nfacct-name session-input-$MARK >>>> iptables -t filter -A OUTPUT -m mark --mark $MARK/0xFFFF0000 \ >>>> -m nfacct --nfacct-name session-output-$MARK >>> >>> >>> >>> That sounds reasonable to me. I don't think we need 2^24 ids, we >>> should be happy with 2^16 applications :) >>> >> >> I thought so too . . . I can't imagine (at least for the near-term) >> having more the 2^16 apps installed. In the process of testing how >> Sessions work in Connman I believe I've stumbled upon either a bug in >> the Sessions implementation or an intended (purposeful) behavior. > > > The code is pretty new, so it is quite likely you find bugs. Yes, I think it is a bug (or an unexpected use case that may not have been considered). > >> I >> rather hope it's a bug since otherwise it will force me to put a >> "shim" in front of the Connman Session API. What I have observed is >> that for *every* session that is created, a new set of iptable rules >> is created . . . even if the same user/group/SELinux context is used >> to create the session. > > > Yeah, the assumption is that each application uses it's own unique > identifier. That code doesn't check if more then one Session uses > the same identifier (GID). So this is a bug. Glad you agree. > >> For instance, if I have two applications (both >> the same user - with a session policy keyed to the UID) and they >> create a Session instance then in the iptable's "mangle" table >> (OUTPUT) looks something like this: >> >> Chain connman-OUTPUT (1 references) >> pkts bytes target prot opt in out source >> destination >> 20 1134 MARK all -- * * 0.0.0.0/0 >> 0.0.0.0/0 owner UID match 1000 MARK set 0x100 >> 20 1134 MARK all -- * * 0.0.0.0/0 >> 0.0.0.0/0 owner UID match 1000 MARK set 0x101 >> >> So it would appear the *last* session that is created will effectively >> mark (and clobber) the first marking for the packet (0x101 mark >> clobbers the earlier 0x100 mark since it's last in the chain). I hope >> this is *not* what was intended. I expected that iptable rules for >> Session policies for the same UID/GID/SELinux context would "share" >> the same session (and thus statistics). So if two applications running >> as the same UID/GID/SELinux context requested a Connman Session, the >> first requestor would create it while the second application would get >> a "reference" to that session. This session would remain valid until >> the last application (with the same UID/GID/SELinux context) destroyed >> the session. In a sense the Sessions become reference counted per >> session policy. As it stands today it would appear Connman creates far >> more iptable rules than necessary to support multiple applications >> running as the same user (or in the same group or SELinux context). Am >> I correct in assuming this is a design error in the current >> implementation of Sessions? > > > You are right. We need to fix this. Patches? :D I can certainly work on this now that I understand what was intended. Just didn't want to invest the time if Connman was operating under a different premise or approach. > >>>> As you can see, setting the Connman MARK is no longer destructive to a >>>> value that might already exist in the lower 16-bits of the 32-bit >>>> word. Likewise, when reading and comparing the value the lower 16-bits >>>> of the 32-bits value are effectively masked out so it won't impact the >>>> Connman session match test. >>>> >>>> Part of my problem is that I need to create additional iptable rules >>>> that place data-caps (e.g. a quota) on certain sessions (apps) which >>>> are then optionally partitioned into additional groups. I can use the >>>> power/flexibility of iptables to implement this logic but I need to >>>> cooperatively use the same netfilter 32-bit value to store additional >>>> information about the connection and their associated packets. This >>>> change would help Connman behave as a better netfilter citizen while >>>> allowing me to piggy-back on top of the existing marking done by >>>> Connman. >>> >>> >>> >>> Well, the quota thing is something we want also to support natively >>> with sessions. That is also why count the packets (currently with >>> nfacct but we don't use that information yet). >>> >> >> I'm sure you realize that you don't explicitly need nfacct to collect >> statistics. Granted, nfacct gives you nicely named buckets you can >> access with the nfacct utility and likely over netlink as well. But >> each iptable's rule has a byte/packet count associated with it. > > > Dumping the iptables all the time is kind of excessive. Agreed . . . I'd rather not poll for these stats. But they are available and I could keep the frequency of polling to a minimum since the quota enforcement is done within a netfilter rule rather than trying to track and apply it from a user-space program. > >> So if >> a packet merely passes through a rule (a simple "do nothing" rule) it >> will increment that rule's counters. Plus, iptables gives give you a >> way to query/reset the stats for a specific rule if I'm not mistaken. > > > Yes, that would probably also work but this is a polling which I > try to avoid. Agreed. Polling is generally bad . . . but there are times when you might have no other choice. > >>>> I'm willing to make the necessary code changes to implement this >>>> solution. I'm just seeking feedback of whether a better solution >>>> exists (that I'm unaware of) or perhaps recommendations on my >>>> approach. Of course any patches I make would be available to the >>>> community and hopefully could eventually be integrated into the main >>>> baseline. >>> >>> >>> >>> I am happy to see patches! >>> >>> cheers, >>> daniel >> >> >> I'm really interested in the direction you're headed with Connman >> Sessions. I'd like to leverage this work and perhaps contribute the >> project's generic parts for the solutions I devise. I realize not >> everyone has similar needs but it would appear (at least so far) >> Connman's goals are fairly closely aligned with mine. > > > That is great to hear. We really should strive to make it useful for > more than only my use cases. Therefore I am really happy if you > join the effort to push forward with the Session API and make it > a great feature! > > cheers, > daniel _______________________________________________ connman mailing list connman@connman.net https://lists.connman.net/mailman/listinfo/connman