[PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)
Robin Hack
rhack@redhat.com
Sun Nov 17 10:18:00 GMT 2013
On Wed, Nov 13, 2013 at 05:18:35PM -0500, Frank Ch. Eigler wrote:
Hi Frank.
Thanks again for comments. I did some changes, but comments and changes
are still needed.
>
> Hi, Robin -
>
> rhack wrote:
>
> > [...] Then I decided to write this patch. Patch is only draft now
> > and comments are very welcome.
>
> Nice. A few code comments:
>
> The use of TMP_STAP_RETVALUE / MAXLEN in the embedded-c function is a
> little clumsy. Have you considered using ordinarily named variables
> to track the remainder base/length of STAP_RETVALUE,
It's fixed.
> and doing the
> RETVALUE_INC_SKIP dance inlined instead of as a macro?
I apologize here, but this part is not clear enought for me.
> What about delimiters between the data corresponding to multiple SA_* selections?
I changed approach. Now I export values direct to probes.
Delimiters will be good in tapset library.
>
>
> > Very easy example are attached too.
>
> It might be even simpler if the related tapset functions all get this
> kind of stuff, but perhaps plopped into a macro for easier handling:
>
> probe syscall.bind = ... {
> %( systemtap_v >= "2.5" %?
> if (_struct_sockaddr_u_sa_family(my_addr_uaddr, addrlen) =~ "AF_INET.*") {
> uaddr_ip = _struct_sockaddr_u_ip_addr(my_addr_uaddr, addrlen)
> uaddr_ip_port = ...
> }
> %)
>
> where the whole %( %) block could be @defined in a macro, kind of like
> _nfs_data_timestamp in tapset/linux/nfs_proc.stpm.
>
>
> > What is not solved in this patch:
> > * Error handling if wrong struct is passed - now it's just return empty ("") string. Maybe throw exception will be better.
I hope, that this will be part of tapset.
> > * Expansion to syscall.connect probe.
Done :).
> > * Write tapset shell for new internal functions.
In progress.
>
> Yup, plus a test case (e.g., a testsuite/buildok file).
I added some tests.
>
> Thanks!
>
> - FChE
-------------- next part --------------
diff --git a/tapset/linux/aux_syscalls.stp b/tapset/linux/aux_syscalls.stp
index 0f9c9e4..1513150 100644
--- a/tapset/linux/aux_syscalls.stp
+++ b/tapset/linux/aux_syscalls.stp
@@ -280,7 +280,7 @@ function _struct_compat_itimerval_u:string(uaddr:long)
%}
%{
-// Needed for function _struct_sockaddr_u. Unfortunately cannot be
+// Needed for function _struct_sockaddr_u_impl. Unfortunately cannot be
// inlined into the function since these header files define static
// functions themselves.
#include <linux/socket.h>
@@ -288,18 +288,75 @@ function _struct_compat_itimerval_u:string(uaddr:long)
#include <linux/netlink.h>
%}
+%{
+// Enum for _struct_sockaddr_u_* functions.
+typedef enum {
+ SA_PRETTY = 1,
+ SA_IP_ADDR = 2,
+ SA_TCP_PORT = 4,
+ SA_FAMILY = 8,
+ SA_IPV6_FLOWINFO = 16,
+ SA_IPV6_SCOPE_ID = 32,
+} sa_dispatch;
+%}
+
+function _struct_sockaddr_u_ip_addr:string(uaddr:long, len:long)
+{
+ return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR %});
+}
+
+function _struct_sockaddr_u_tcp_port:string(uaddr:long, len:long)
+{
+ return _struct_sockaddr_u_impl(uaddr, len, %{ SA_TCP_PORT %});
+}
+
+function _struct_sockaddr_u_ip_addr_tcp_port:string(uaddr:long, len:long)
+{
+ return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR | SA_TCP_PORT %});
+}
+
+function _struct_sockaddr_u_sa_family:string(uaddr:long, len:long)
+{
+ return _struct_sockaddr_u_impl(uaddr, len, %{ SA_FAMILY %});
+}
+
+function _struct_sockaddr_u_ipv6_flowinfo:string(uaddr:long, len:long)
+{
+ return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_FLOWINFO %});
+}
+
+function _struct_sockaddr_u_ipv6_scope_id:string(uaddr:long, len:long)
+{
+ return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_SCOPE_ID %});
+}
+
function _struct_sockaddr_u:string(uaddr:long, len:long)
+{
+ return _struct_sockaddr_u_impl(uaddr, len, %{ SA_PRETTY %});
+}
+
+function _struct_sockaddr_u_impl:string(uaddr:long, len:long, what:long)
%{ /* pure */
#include <linux/version.h>
#include <linux/in6.h>
#include <linux/un.h>
#include <linux/if_packet.h>
+ sa_dispatch what = (sa_dispatch)STAP_ARG_what;
+
char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
char buf[128];
size_t len = STAP_ARG_len < 128 ? STAP_ARG_len : 128;
struct sockaddr *sa = (struct sockaddr *)buf;
+// Don't use this macro outside of if (what & ... ) statement!
+// (n - 1) mean: cut of null char
+#define RETVALUE_INC_SKIP() do {stap_retvalue += (n); maxstringlen -= (n - 1);} while (0)
+ char *stap_retvalue = (char *)(unsigned long)STAP_RETVALUE;
+ int maxstringlen = MAXSTRINGLEN;
+ size_t n;
+
+
if (ptr == NULL)
{
strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
@@ -320,60 +377,163 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
#define DADDR (&inet->daddr)
#endif
+
// Use kernel builtin instead of picking up user space ntohs (function).
#define _stp_ntohs be16_to_cpu
if ((sa->sa_family == AF_INET) && (len == sizeof(struct sockaddr_in)))
{
struct sockaddr_in *sin = (struct sockaddr_in *)buf;
-#ifndef NIPQUAD_FMT // kver >= 2.6.36
- snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
- &sin->sin_addr, _stp_ntohs(sin->sin_port));
+
+ if (what & SA_PRETTY)
+ {
+#ifndef NIPQUAD_FMT // kver >= 2.6.36
+ snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
+ &sin->sin_addr, _stp_ntohs(sin->sin_port));
#else
- snprintf(STAP_RETVALUE, MAXSTRINGLEN,
- "{AF_INET, " NIPQUAD_FMT ", %d}",
- NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
-#endif
+ snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+ "{AF_INET, " NIPQUAD_FMT ", %d}",
+ NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
+#endif
+ return;
+ }
+
+ if (what & SA_FAMILY)
+ {
+ n = strlcpy(stap_retvalue, "AF_INET", maxstringlen);
+ RETVALUE_INC_SKIP();
+ }
+
+ if (what & SA_IP_ADDR)
+ {
+#ifndef NIPQUAD_FMT // kver >= 2.6.36
+ n = snprintf(stap_retvalue, maxstringlen, "%pI4", &sin->sin_addr);
+#else
+ n = snprintf(stap_retvalue, maxstringlen, NIPQUAD_FMT,
+ NIPQUAD(sin->sin_addr));
+#endif
+ RETVALUE_INC_SKIP();
+ }
+
+ if (what & SA_TCP_PORT)
+ {
+ n = snprintf(stap_retvalue, maxstringlen, "%d",
+ _stp_ntohs(sin->sin_port));
+ RETVALUE_INC_SKIP();
+ }
}
else if ((sa->sa_family == AF_UNIX)
&& (len == sizeof(struct sockaddr_un)))
- {
- struct sockaddr_un *sun = (struct sockaddr_un *)buf;
- snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
- sun->sun_path);
+ {
+ struct sockaddr_un *sun = (struct sockaddr_un *)buf;
+
+ if (what & SA_PRETTY)
+ {
+ snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
+ sun->sun_path);
+ } else if (what & SA_FAMILY)
+ {
+ strlcpy(STAP_RETVALUE, "AF_UNIX", MAXSTRINGLEN);
+ } else
+ {
+ strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+ }
}
else if ((sa->sa_family == AF_NETLINK)
&& (len == sizeof(struct sockaddr_nl)))
{
struct sockaddr_nl *nl = (struct sockaddr_nl *)buf;
- snprintf(STAP_RETVALUE, MAXSTRINGLEN,
- "{AF_NETLINK, pid=%d, groups=%08x}",
- nl->nl_pid, nl->nl_groups);
+
+ if (what & SA_PRETTY) {
+ snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+ "{AF_NETLINK, pid=%d, groups=%08x}",
+ nl->nl_pid, nl->nl_groups);
+ } else if (what & SA_FAMILY)
+ {
+ strlcpy(STAP_RETVALUE, "AF_NETLINK", MAXSTRINGLEN);
+ } else
+ {
+ strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+ }
}
else if ((sa->sa_family == AF_INET6)
&& (len == sizeof(struct sockaddr_in6)))
{
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)buf;
+
+ if (what & SA_PRETTY)
+ {
#ifndef NIP6_FMT // kver >= 2.6.36
- snprintf(STAP_RETVALUE, MAXSTRINGLEN,
- "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
- _stp_ntohs(sin->sin6_port));
+ snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+ "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
+ _stp_ntohs(sin->sin6_port));
#else
- snprintf(STAP_RETVALUE, MAXSTRINGLEN,
- "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
- _stp_ntohs(sin->sin6_port));
+ snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+ "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
+ _stp_ntohs(sin->sin6_port));
#endif
+ return;
+ }
+
+ if (what & SA_FAMILY)
+ {
+ n = strlcpy(stap_retvalue, "AF_INET6", maxstringlen);
+ RETVALUE_INC_SKIP();
+ }
+
+ if (what & SA_IP_ADDR)
+ {
+#ifndef NIP6_FMT // kver >= 2.6.36
+ n = snprintf(stap_retvalue, maxstringlen,
+ "%pI6", &sin->sin6_addr);
+#else
+ n = snprintf(stap_retvalue, maxstringlen,
+ NIP6_FMT, NIP6(sin->sin6_addr));
+#endif
+ RETVALUE_INC_SKIP();
+ }
+
+ if (what & SA_TCP_PORT)
+ {
+ n = snprintf(stap_retvalue, maxstringlen,
+ "%d", _stp_ntohs(sin->sin6_port));
+ RETVALUE_INC_SKIP();
+ }
+
+ if (what & SA_IPV6_FLOWINFO)
+ {
+ n = snprintf(stap_retvalue, maxstringlen,
+ "%d", sin->sin6_flowinfo);
+ RETVALUE_INC_SKIP();
+ }
+
+ if (what & SA_IPV6_SCOPE_ID)
+ {
+ n = snprintf(stap_retvalue, maxstringlen,
+ "%d", sin->sin6_flowinfo);
+ RETVALUE_INC_SKIP();
+ }
}
else if ((sa->sa_family == AF_PACKET)
- && (len == sizeof(struct sockaddr_ll)))
+ && (len == sizeof(struct sockaddr_ll)))
{
struct sockaddr_ll *sll = (struct sockaddr_ll *)buf;
- snprintf(STAP_RETVALUE, MAXSTRINGLEN,
- "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
- (int)sll->sll_protocol, sll->sll_ifindex,
- (int)sll->sll_hatype, (int)sll->sll_pkttype,
- (int)sll->sll_halen,
- (long long)(*(uint64_t *)sll->sll_addr));
+
+ if (what & SA_PRETTY)
+ {
+ snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+ "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
+ (int)sll->sll_protocol, sll->sll_ifindex,
+ (int)sll->sll_hatype, (int)sll->sll_pkttype,
+ (int)sll->sll_halen,
+ (long long)(*(uint64_t *)sll->sll_addr));
+ } else if (what & SA_FAMILY)
+ {
+ strlcpy(STAP_RETVALUE, "AF_PACKET", MAXSTRINGLEN);
+ } else
+ {
+ strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+ }
}
else
{
@@ -389,6 +549,8 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
"{unknown sockaddr with salen=%d}", (int)len);
}
}
+
+#undef RETVALUE_INC_SKIP
%}
function _struct_rlimit_u:string(uaddr:long)
diff --git a/tapset/linux/nd_syscalls.stp b/tapset/linux/nd_syscalls.stp
index f2daa01..5121751 100644
--- a/tapset/linux/nd_syscalls.stp
+++ b/tapset/linux/nd_syscalls.stp
@@ -247,6 +247,7 @@ probe nd_syscall.bind = kprobe.function("sys_bind") ?
sockfd = int_arg(1)
my_addr_uaddr = pointer_arg(2)
addrlen = int_arg(3)
+ @_af_inet_info_u(my_addr_uaddr, addrlen)
argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(my_addr_uaddr, addrlen), addrlen)
}
probe nd_syscall.bind.return = kprobe.function("sys_bind").return ?
@@ -586,6 +587,7 @@ probe nd_syscall.connect = kprobe.function("sys_connect") ?
sockfd = int_arg(1)
serv_addr_uaddr = pointer_arg(2)
addrlen = int_arg(3)
+ @_af_inet_info_u(serv_addr_uaddr, addrlen)
argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(serv_addr_uaddr, addrlen), addrlen)
}
probe nd_syscall.connect.return = kprobe.function("sys_connect").return ?
diff --git a/tapset/linux/syscalls.stp b/tapset/linux/syscalls.stp
index 13fb92f..d8e1d05 100644
--- a/tapset/linux/syscalls.stp
+++ b/tapset/linux/syscalls.stp
@@ -199,6 +199,7 @@ probe syscall.bind = kernel.function("sys_bind").call ?
sockfd = $fd
my_addr_uaddr = $umyaddr
addrlen = $addrlen
+ @_af_inet_info_u(my_addr_uaddr, addrlen)
argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($umyaddr, $addrlen), $addrlen)
}
probe syscall.bind.return = kernel.function("sys_bind").return ?
@@ -472,6 +473,7 @@ probe syscall.connect = kernel.function("sys_connect").call ?
sockfd = $fd
serv_addr_uaddr = $uservaddr
addrlen = $addrlen
+ @_af_inet_info_u(serv_addr_uaddr, addrlen)
argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($uservaddr, $addrlen), $addrlen)
}
probe syscall.connect.return = kernel.function("sys_connect").return ?
diff --git a/tapset/linux/syscalls.stpm b/tapset/linux/syscalls.stpm
new file mode 100644
index 0000000..0ab18ab
--- /dev/null
+++ b/tapset/linux/syscalls.stpm
@@ -0,0 +1,24 @@
+// Macros for syscalls.stp and nd_syscalls.stp
+// Copyright (C) 2013 Red Hat
+//
+// Author : Robin Hack <rhack@redhat.com>
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+@define _af_inet_info_u(my_addr_uaddr, addrlen)
+%(
+ %( systemtap_v >= "2.5" %?
+ uaddr_af = _struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen)
+ if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) =~ "AF_INET.*") {
+ uaddr_ip = _struct_sockaddr_u_ip_addr(@my_addr_uaddr, @addrlen)
+ uaddr_ip_port = _struct_sockaddr_u_tcp_port(@my_addr_uaddr, @addrlen)
+ if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) == "AF_INET6") {
+ uaddr_ipv6_flowinfo = _struct_sockaddr_u_ipv6_flowinfo(@my_addr_uaddr, @addrlen)
+ uaddr_ipv6_scope_id = _struct_sockaddr_u_ipv6_scope_id(@my_addr_uaddr, @addrlen)
+ }
+ }
+ %)
+%)
diff --git a/testsuite/buildok/aux_syscalls-embedded.stp b/testsuite/buildok/aux_syscalls-embedded.stp
index 1fb5114..51b02c1 100755
--- a/testsuite/buildok/aux_syscalls-embedded.stp
+++ b/testsuite/buildok/aux_syscalls-embedded.stp
@@ -14,6 +14,14 @@ probe begin {
print (_struct_itimerval_u(0))
print (_struct_compat_itimerval_u(0))
print (_struct_sockaddr_u(0,0))
+%( systemtap_v >= "2.5" %?
+ print (_struct_sockaddr_u_ip_addr(0,0))
+ print (_struct_sockaddr_u_tcp_port(0,0))
+ print (_struct_sockaddr_u_sa_family(0,0))
+ print (_struct_sockaddr_u_ipv6_flowinfo(0,0))
+ print (_struct_sockaddr_u_ipv6_scope_id(0,0))
+ print (_struct_sockaddr_u_impl(0,0,0))
+%)
print (_struct_rlimit_u(0))
print (_fildes_index_u(0, 0))
diff --git a/testsuite/buildok/nd_syscalls-detailed.stp b/testsuite/buildok/nd_syscalls-detailed.stp
index 8152f8d..4c9e0ed 100755
--- a/testsuite/buildok/nd_syscalls-detailed.stp
+++ b/testsuite/buildok/nd_syscalls-detailed.stp
@@ -74,8 +74,13 @@ probe nd_syscall.bdflush.return ?
probe nd_syscall.bind
{
printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+ printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
+%:
printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
+%)
}
+
probe nd_syscall.bind.return
{
printf("%s, %s\n", name, retstr)
@@ -194,7 +199,11 @@ probe nd_syscall.close.return
probe nd_syscall.connect
{
printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+ printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
+%:
printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
+%)
}
probe nd_syscall.connect.return
{
diff --git a/testsuite/buildok/syscalls-detailed.stp b/testsuite/buildok/syscalls-detailed.stp
index e1c626c..17544f7 100755
--- a/testsuite/buildok/syscalls-detailed.stp
+++ b/testsuite/buildok/syscalls-detailed.stp
@@ -74,7 +74,12 @@ probe syscall.bdflush.return ?
probe syscall.bind
{
printf("%s, %s\n", name, argstr)
+
+%( systemtap_v >= "2.5" %?
+ printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
+%:
printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
+%)
}
probe syscall.bind.return
{
@@ -194,7 +199,11 @@ probe syscall.close.return
probe syscall.connect
{
printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+ printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
+%:
printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
+%)
}
probe syscall.connect.return
{
More information about the Systemtap
mailing list