Hi, I''d like to get values from the struct sockaddr_in which is passed to accept . At the time of entry this struct has still no values. How could I access the struct at return? The usage of arg0 seems useless, as this is a new filedesriptor. Does the copyin at entry make sense at all? fbt:sockfs:accept:entry { newsock = (struct sockaddr_in*)copyin(arg1, arg2); */ } fbt:sockfs:accept:return { /* ??? */ } thank you, goinsane Message was edited by: goinsane -- This message posted from opensolaris.org
krishnan parthasarathi - Sun Microsystems - Bangalore India
2010-Sep-17 10:12 UTC
[dtrace-discuss] values from a struct
Hi goinsane,> I''d like to get values from the struct sockaddr_in which is passed to accept . At the time of entry this struct has still no values. How could I access the struct at return? The usage of arg0 seems useless, as this is a new filedesriptor. Does the copyin at entry make sense at all? >The copyin at the entry probe does not make sense. Since the address of the sockaddr_in structure will not be available in argN builtin variables, you must store the addresses you are interested in in a thread local variable. On the return probe you can use copyin builtin method to get the contents of the sockaddr structure. The modified script would look like the following, fbt:sockfs:accept:entry { self->sockaddr_ref = arg1; self->sockaddr_len = arg2; } fbt:sockfs:accept:return { self->sockaddr_content = (struct sockaddr_in*) copyin(self->sockaddr_ref, self->sockaddr_len); /* whatever your script intends to with the sockaddr structure */ } cheers, Krishnan> fbt:sockfs:accept:entry > { > newsock = (struct sockaddr_in*)copyin(arg1, arg2); */ > } > > > fbt:sockfs:accept:return > { > /* ??? */ > } > > > thank you, > > goinsane > > Message was edited by: goinsane >
Helle Krishnan, thank you! I thought it''s not possible to store an address of a struct. Do you know how to extract the current size of the struct?>From accept(3socket):" The argument addrlen is a value-result parameter. Initially, it contains the amount of space pointed to by addr; on return it contains the length in bytes of the address returned. " Unfortunately, D returns an error at the copyin: dtrace: error on enabled probe ID 2 (ID 28357: fbt:sockfs:accept:return): out of scratch space in action #1 at DIF offset 52 If I print the value of arg2, it shows incredible 4290770780 . cheers, chris -- This message posted from opensolaris.org
On 09/17/10 07:40, goinsane wrote:> Helle Krishnan, > > thank you! I thought it''s not possible to store an address of a struct. > Do you know how to extract the current size of the struct? >>From accept(3socket): > > " The argument addrlen is a value-result parameter. Initially, > it contains the amount of space pointed to by addr; on > return it contains the length in bytes of the address > returned. " > > Unfortunately, D returns an error at the copyin: > > dtrace: error on enabled probe ID 2 (ID 28357: fbt:sockfs:accept:return): out of scratch space in action #1 at DIF offset 52 > > > If I print the value of arg2, it shows incredible 4290770780 .That''s because (just like the accept() call itself), it''s actually a pointer to the value, not the value itself. You have to do a copyin(arg2, 4) first. -- James Carlson 42.703N 71.076W <carlsonj at workingcode.com>
Yes, you''re right, the manpage expresses this, too. But how to get the value? copyin returns the address of the scratch buffer. could this be used as argument of the 2nd copyin of fbt:sockfs:accept:return ? fbt:sockfs:accept:entry { self->sockaddr = arg1; self->socklen = (int*)copyin(arg2, 4); } fbt:sockfs:accept:return { self->sockcont = (struct sockaddr_in*)copyin(self->sockaddr, self->socklen); } Unforntunately, I'' m getting an error within the 1st probe: dtrace: error on enabled probe ID 1 (ID 28356: fbt:sockfs:accept:entry): invalid address (0x0) in action #2 at DIF offset 52 -- This message posted from opensolaris.org
On 09/17/10 09:34, goinsane wrote:> Yes, you''re right, the manpage expresses this, too. > But how to get the value? copyin returns the address of the scratch buffer. could this be used as argument of the 2nd copyin of fbt:sockfs:accept:return ? > > fbt:sockfs:accept:entry > { > self->sockaddr = arg1; > self->socklen = (int*)copyin(arg2, 4); > }It''s an in-out parameter. The value at entry is just the _maximum_ size of the caller''s buffer, and not the _actual_ size of the returned data.> fbt:sockfs:accept:return > { > self->sockcont = (struct sockaddr_in*)copyin(self->sockaddr, self->socklen); > }I would do this in the entry clause: self->sockaddr = arg1; self->socklenp = arg2; and then this in the return clause: self->socklen = *(int *)copyin(self->socklenp, 4); self->sockcont = (struct sockaddr_in *)copyin(self->sockaddr, self->socklen); (This assumes the application is 32-bit or at least that the system is little-endian. Things get more complicated if you have to deal with 64-bit big-endian systems.) To be really robust, you could have multiple return causes -- one to get the return length, another to check it and fetch the contents, still another to look at the sa_family, and so on. -- James Carlson 42.703N 71.076W <carlsonj at workingcode.com>
> On 09/17/10 09:34, goinsane wrote: > > Yes, you''re right, the manpage expresses this, too. > > > But how to get the value? copyin returns the > address of the scratch buffer. could this be used as > argument of the 2nd copyin of > fbt:sockfs:accept:return ? > > > > fbt:sockfs:accept:entry > > { > > self->sockaddr = arg1; > > self->socklen = (int*)copyin(arg2, 4); > > } > > It''s an in-out parameter. The value at entry is just > the _maximum_ size > of the caller''s buffer, and not the _actual_ size of > the returned data. > > > fbt:sockfs:accept:return > > { > > self->sockcont = (struct > sockaddr_in*)copyin(self->sockaddr, self->socklen); > > } > > I would do this in the entry clause: > > self->sockaddr = arg1; > self->socklenp = arg2; > > and then this in the return clause: > > self->socklen = *(int *)copyin(self->socklenp, 4);Oh, I forgot to derefence it. I should really refresh my knowledge of C ...> self->sockcont = (struct sockaddr_in > n *)copyin(self->sockaddr, > self->socklen); > > (This assumes the application is 32-bit or at least > that the system is > little-endian. Things get more complicated if you > have to deal with > 64-bit big-endian systems.) >Hm, that''s a point I had not noticed yet. I expected the D scripts running independent from the system''s arch. But as it becomes more complex, it seems this has to be handled, too. Right now, I''m running at 64 bit i86pc . I''m getting a value of the port (have to verify it), but no value of the ip address. self->port = self->sockcont->sin_port; self->ip_int = (uint_t)self->sockcont->sin_addr.s_addr;> To be really robust, you could have multiple return > causes -- one to get > the return length, another to check it and fetch the > contents, still > another to look at the sa_family, and so on.That''s the one I''ll try next. Tank you very much, James!> > -- > James Carlson 42.703N 71.076W > <carlsonj at workingcode.com> > _______________________________________ > dtrace-discuss mailing list > dtrace-discuss at opensolaris.org >-- This message posted from opensolaris.org
goinsane wrote:>> (This assumes the application is 32-bit or at least >> that the system is >> little-endian. Things get more complicated if you >> have to deal with >> 64-bit big-endian systems.) >> > > Hm, that''s a point I had not noticed yet. I expected the D scripts running independent from the system''s arch. But as it becomes more complex, it seems this has to be handled, too.D scripts run in the context of the kernel. If you''ve got a 64-bit kernel, then your D scripts run as (effectively) 64-bit applications. User-space applications on a 64-bit system, though, may be either 32-bit or 64-bit; the system supports both simultaneously. That''s what adds in a bit of complexity. Things running in the kernel (such as D scripts) need to be aware of what flavor of application is out there when they go mucking around with application data structures -- as with copyin.> Right now, I''m running at 64 bit i86pc . I''m getting a value of the port (have to verify it), but no value of the ip address. > > self->port = self->sockcont->sin_port; > self->ip_int = (uint_t)self->sockcont->sin_addr.s_addr;Don''t forget that the port number will be in network (big-endian) byte order. As for the problem with the IP address, I don''t know what could be going on. You might want to try a truss -vall to see if the values you''re getting are the ones you''re expecting. The alignment of sockaddr_in is such that I''d expect it to work fine over the 32/64 boundary without special handling, so if you''re seeing unexpected behavior here, it''s time to start dumping everything -- start by printing out the length of the structure that''s being copied (perhaps that''s wrong) and the first few bytes of the structure to see if it''s what you expect. -- James Carlson 42.703N 71.076W <carlsonj at workingcode.com>
This becomes interesting. truss shows an ipv6 address for some processes, like sshd (ipv4 encapsulated in ipv6), although there is no configured ipv6 interface. 909: accept(3, 0x08047A10, 0x08047E78, SOV_DEFAULT) = 4 909: AF_INET6 name = ::ffff:172.31.70.6 port = 64625 When the probe fbt:sockfs:accept:return is fired , af_family is set to 26 (INET6) instead of 2 (INET). The return of an ipv6 address seems to be the reason for the value of 0 of (uint_t)self->sockcont->sin_addr.s_addr . I still have no glue how the struct sin_addr for ipv6 does look like, if and how it differs from the original ipv4 one. Is there a way to find out the structs getting accessed when a probe is fired? I''ve create created a perlscript, which uses IO::Socket::INET to create a listening socket. truss return the address family AF_INET and the ipv4 address. 23523: accept(4, 0x080475E8, 0x08047A00, SOV_DEFAULT) = 5 23523: AF_INET name = 172.31.70.6 port = 64622 With the following D I could catch the source ip and port. You''re right, I''ve to distinguish the endianness. So it won''t work on sparc. What predicate could be used to differentiate between little and big endian? Do you see a simpler way of the bit operations I''m doing to get the port and ip? #!/usr/sbin/dtrace -qCs #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> fbt:sockfs:accept:entry / execname == "tcps.pl" / { self->sockaddr = arg1; self->socklenp = arg2; } fbt:sockfs:accept:return / self->socklenp && execname == "tcps.pl" / { self->socklen = *(int *)copyin(self->socklenp, 4); self->sockcont = (struct sockaddr_in *)copyin(self->sockaddr, self->socklen); self->sockcont_nofamily = (struct sockaddr *)copyin(self->sockaddr, self->socklen); self->port = self->sockcont->sin_port; self->portB1 = self->port & 0xFF00; self->portB1 >>= 8; self->portB2 = self->port & 0xFF; self->portB2 <<= 8; self->portOk = self->portB2 | self->portB1; self->ip = (uint_t)self->sockcont->sin_addr.s_addr; oct4 = self->ip >> 24; oct3 = self->ip >> 16; oct2 = self->ip >> 8; oct1 = self->ip; oct1 &= 255; oct2 &= 255; oct3 &= 255; oct4 &= 255; printf("Process %s , Pid: %d got request from %d.%d.%d.%d (src Port %d)\n", execname, pid, oct1, oct2, oct3, oct4, self->portOk); /* printf("address family const got : %d\n", self->sockcont_nofamily->sa_family); printf("address family const of ipv6: %d\n", AF_INET6); printf("len %d\n", self->socklen); printf("struct size: %d\n", sizeof( self->sockcont)); printf("port: %d ip: %d port1: %d port2: %d portall: %d\n", self->port, self->ip, self->portB1, self->portB2, self->portOk); printf("socklen: %d \n", self->socklen); printf("struct addrr: %x \n", self->sockaddr); printf("struct len: %x\n", self->socklenp); */ } -- This message posted from opensolaris.org
goinsane wrote:> This becomes interesting. truss shows an ipv6 address for some processes, like sshd (ipv4 encapsulated in ipv6), although there is no configured ipv6 interface. > > 909: accept(3, 0x08047A10, 0x08047E78, SOV_DEFAULT) = 4 > 909: AF_INET6 name = ::ffff:172.31.70.6 port = 64625 > > > When the probe fbt:sockfs:accept:return is fired , af_family is set to 26 (INET6) instead of 2 (INET). The return of an ipv6 address seems to be the reason for the value of 0 of (uint_t)self->sockcont->sin_addr.s_addr . I still have no glue how the struct sin_addr for ipv6 does look like, if and how it differs from the original ipv4 one. > > Is there a way to find out the structs getting accessed when a probe is fired?No. The program itself doesn''t even know that. That''s why sa_family exists. You''re supposed to switch out based on that value. In a D script, you "switch out" by having multiple probes with different conditions.> With the following D I could catch the source ip and port. You''re right, I''ve to distinguish the endianness. So it won''t work on sparc. > > What predicate could be used to differentiate between little and big endian? > Do you see a simpler way of the bit operations I''m doing to get the port and ip?There are two distinct endian issues here. On SPARC, the network values (port numbers and addresses) will all be in the right order, but you have to pay attention to 32/64. I''ve forgotten how to do that, but I''m sure there''s someone on this list who knows. On x86, the network values will all be in reverse order, because network data is big-endian. That means you have to swap it yourself. I''d recommend having this clause first: fbt:sockfs:accept:entry { self->socklenp = 0; } That way, all tests after the first one can be "/self->socklenp/" rather than doing a string compare on execname. It should be a little better performing.> fbt:sockfs:accept:return > / self->socklenp && execname == "tcps.pl" / > { > self->socklen = *(int *)copyin(self->socklenp, 4); > self->sockcont = (struct sockaddr_in *)copyin(self->sockaddr, self->socklen);That''s where I think you''re going wrong. You need to copy in the family first, so something like this: self->family = *(short *)copyin(self->sockaddr, sizeof (short)); Then just end that clause and start a new one: fbt:sockfs:accept:return /self->socklenp && self->family == 2/ { /* this is the AF_INET case */ You can then copy in the full sockaddr_in and drive on. For AF_INET6, you have to use sockaddr_in6 and sin6_addr. See the netinet/in.h header file and the inet6(7P) man page. D trace clauses are like ''if'' statements in other languages. You can have multiple, and they''re executed in the order they appear in the file. -- James Carlson 42.703N 71.076W <carlsonj at workingcode.com>