How do I find out my multicast (Bonjour) hostname? - macos

I've registered a record using the Bonjour API. Now I want to know the contents of the record I just published. I created it by specifying a NULL hostname, meaning, "use the daemon's default", but I can't find a simple way to query what that is!
With avahi, it's easy: I call avahi_client_get_host_name() to get the starting value of the machine's hostname.
For both avahi and Bonjour, the value of the SRV record can change during the lifetime of the registration - if the registration was done with a NULL hostname, the record's hostname is updated automatically when necessary. All I want here is a way to get the initial value of the hostname, at the time when I perform the registration.
Note that on my Snow Leopard test machine, the default multicast hostname is not the same as the machine's name from gethostname(2).
Four solutions I can think of:
Grab hostname in my process. It may be in there somewhere. I did a strings(3) search on a memory dump of my process, and found four instances of the multicast hostname in my address space, but that could be coincidence given the name is used for other things. Even if the string I'm after is in my process somewhere, I can't find an API to retrieve it sanely.
Query the hostname from the daemon. There may be some query I can send over the mach port to the daemon that fetches it? I can't find an API again. The relevant chunk of code is in the uDNS.c file in mDNSResponder, and doesn't seem to be exposed via the RPC interface.
I could just lookup the service I registered. This may involve a bit of network traffic though, so unless there's some guarantee that won't happen, I'm loathe to do it.
Re-implement the logic in uDNS.c. It grabs the machine's hostname from a combination of:
Dynamic DNS configuration
Statically configured multicast hostname
Reverse lookup of the primary interface's IPv4 address
It specifically doesn't use gethostname(2) or equivalent
Re-implementing that logic seems infeasible.
At the moment, I'm tending towards doing a lookup to grab the value of the initial SRV registration, but it doesn't seem ideal. What's the correct solution?

I needed to do exactly this. You want to use the ConvertDomainNameToCString macro (included in mDNSEmbeddedAPI.h), and you need access to the core mDNS structure.
Here's how you get the exact Bonjour/Zeroconf hostname that was registered:
char szHostname[512];
extern mDNS m;
ConvertDomainNameToCString(&m.MulticastHostname, szHostname);
I hope this helps you.

For the record, I went with (4), grabbing the machine's configuration to pull together the hostname the daemon is using without having to query it.
static char* getBonjourDefaultHost()
{
char* rv = 0;
#ifdef __APPLE__
CFStringRef name = SCDynamicStoreCopyLocalHostName(NULL);
if (name) {
int len = CFStringGetLength(name);
rv = new char[len*4+1];
CFStringGetCString(name, rv, len*4+1, kCFStringEncodingUTF8);
CFRelease(name);
}
// This fallback is completely incorrect, but why should we care...
// Mac does something crazy like <sysctl hw.model>-<MAC address>.
if (!rv)
rv = GetHostname(); // using gethostname(2)
#elif defined(WIN32)
CHAR tmp[256+1];
ULONG namelength = sizeof(tmp);
DynamicFn<BOOL (WINAPI*)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD)>
GetComputerNameExA_("Kernel32", "GetComputerNameExA");
if (!GetComputerNameExA_.isValid() ||
!(*GetComputerNameExA_)(ComputerNamePhysicalDnsHostname, tmp, &namelength))
tmp[0] = 0;
// Roughly correct; there's some obscure string cleaning mDNSResponder does
// to tidy up funny international strings.
rv = tmp[0] ? strdup(tmp) : strdup("My Computer");
#elif defined(__sun)
// This is exactly correct! What a relief.
rv = GetHostName();
#else
#error Must add platform mDNS daemon scheme
#endif
return rv;
}

From the command line one can obtain the local (Bonjour) hostname using the scutil command:
scutil --get LocalHostName
Programmatically this is obtainable using the kSCPropNetLocalHostName key via the SystemConfiguration Framework.

I know this is already answered, but I went looking to see how to do it with the SystemConfiguration framework based on what Pierz said in the second half of his answer.
This is what I got working, figured it might save someone else googling this some time:
In Swift:
import SystemConfiguration
let store = SCDynamicStoreCreate(nil, "ipmenu" as CFString, nil, nil )
if let hostNames = SCDynamicStoreCopyValue(store, "Setup:/Network/HostNames" as CFString){
if let hostName:String = (hostNames[kSCPropNetLocalHostName]) as? String {
print("Host name:\(hostName)")
}
}

Related

gRPC Proto Buff URL/URI type

Is there a way to use Url or Uri data type inside a message of gRPC? And if not what is the best way to do this?
I am using gRPC and Protocol Buffers for this and I run a backend go app to trigger popup notifications that display in my Flutter app. The notification has a link that takes the user to a webpage when clicked on in my Flutter app.
Right now I am using a String for this, like so:
message NotificationResponse{
string title = 1;
string url = 2;
}
I can't seem to find a way to use Url/Uri as a type. Is there such a thing?
Storing in a string is a totally viable solution. But if you would like to reduce the payload size a little and make the instantiation little bit safer, you could remove the schema part of the url (eg: https://).
To do that you could do the following:
message Url {
enum Schema {
UNSPECIFIED = 0;
HTTP = 1;
HTTPS = 2;
// more if needed
}
Schema schema = 1;
string rest = 2;
}
and then you can use it in your message like this:
message NotificationResponse {
string title = 1;
Url url = 2;
}
This would exclude these non necessary character in the string and reduce the payload size (remove http(s) and ://). Enum are serialized more efficiently than string.
This would make instantiation safer because you can restrict at least the schema that you and other developers can use (in my example, no ftp or even restrict to only https for security).
That has one inconvenience though. You will have to concatenate that back in your client code, but in my opinion this is worth the effort since the concatenation is pretty trivial (change enum value to is text value and add ://).
Note: doing the same enum trick for Domain Name (.com, .net, ...) would not be as trivial and would force you to store the path and the host in different field (not worth it since it increase payload).
Let me know if you need more help.

Best way to get the connected network domain name in Windows

I would like to find out whether the local Windows system is connected to a network domain (instead of a workgroup) and if so, read the domain's name.
I found these Windows API functions to achieve this:
GetEnvironmentVariable('USERDNSDOMAIN')
NetGetJoinInformation
NetServerGetInfo
NetWkstaGetInfo
LookupAccountSid
Are there any advantages or disadvantages between them? (faster, more reliable, more accurate, ...)
Which one would you recommend and why?
LookupAccountSid is more focused on searching for sid, NetServerGetInfo is focused on retrieving server information.
So neither of these applies to you.
The domain name gets from NetGetJoinInformation and NetWkstaGetInfo correspond to USERDOMAIN instead of USERDNSDOMAIN, Depending on the domain name you want.
GetEnvironmentVariable is the function that just get the value of a variable and can be modified by SetEnvironmentVariable at any time (Even though we usually don't do this), so I don't recommend it.
No special group membership is required to successfully execute the
NetGetJoinInformation function.
And it is more pure than NetWkstaGetInfo(according to your requirement)
most direct and efficient here - call LsaQueryInformationPolicy with PolicyDnsDomainInformation. on output you got filled POLICY_DNS_DOMAIN_INFO structure. here will be name and DNS name of the primary domain. and also it SID
If the computer associated with the Policy object is not a member of a
domain, all structure members except Name are NULL or zero.
#include <Ntsecapi.h>
NTSTATUS PrintDomainName()
{
LSA_HANDLE PolicyHandle;
static LSA_OBJECT_ATTRIBUTES oa = { sizeof(oa) };
NTSTATUS status = LsaOpenPolicy(0, &oa, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
if (LSA_SUCCESS(status))
{
PPOLICY_DNS_DOMAIN_INFO ppddi;
if (LSA_SUCCESS(status = LsaQueryInformationPolicy(PolicyHandle, PolicyDnsDomainInformation, (void**)&ppddi)))
{
if (ppddi->Sid)
{
DbgPrint("DnsDomainName: %wZ\n", &ppddi->DnsDomainName);
}
else
{
DbgPrint("%wZ: not a member of a domain\n", &ppddi->Name);
}
LsaFreeMemory(ppddi);
}
LsaClose(PolicyHandle);
}
return status;
}
the NetGetJoinInformation internally do the same - query PolicyDnsDomainInformation, but do this not in your but in remote process (svchost.exe -k networkservice -p -s LanmanWorkstation - LanmanWorkstation service) and many additional calls do. so it less efficient, but and less source code for call this api

Calling XGetErrorText() from X11 error handler

Is it safe to call XGetErrorText from a error handler set by XSetErrorHandler?
E.g.
int errorHandler(Display *dpy, XErrorEvent *err)
{
char buf[BUFLEN];
XGetErrorText(dpy, err->error_code, buf, BUFLEN);
printf("%s\n", buf)
return 0;
}
XSetErrorHandler(errorHandler);
I'm asking because the man page says you should not call any functions (directly or indirectly) on the display that will generate protocol requests but it does not tell if XGetErrorText does.
XGetErrorText doesn't generate any server traffic. It's not supposed to: the server doesn't know your locale, for example, and cannot supply localised messages. XLib can, and indeed does with a couple of local Xrm database lookups.
The source code of XGetErrorText can be viewed e.g. here. We can see that XGetErrorText calls XGetErrorDatabaseText, and this latter function is not even using its dpy parameter.
Each X extension provides its own error-event-to-error-string translation function. This function does accept a dpy parameter, but, just like XGetErrorDatabaseText is not supposed to use it too generate any server traffic. This error-handling function is by default generateed by the XEXT_GENERATE_ERROR_STRING macro here, which just encapsulates another call to XGetErrorDatabaseText.

How do i access netstat data in ruby

I want list of all networking statistics like network connections, routing tables and a number of network interface. How can I do this in Ruby?
I noted, you've tagged this as JRuby as well ... you can get some of the info using Java APIs.
but do not expect to get full routing as (netstat gives you) in the end a gem (or plugin) will use a system call anyways (at least on Java there's no way do get the tables cross-platform) ...
ifaces = java.net.NetworkInterface.getNetworkInterfaces.to_a # all you have
name = ifaces[0].name # name = "number" of interface e.g. "eth0"
ips = ifaces[0].inet_addresses.map { |addr| addr.to_s } # likely IP6/IP4
Explore the API: http://docs.oracle.com/javase/6/docs/api/java/net/NetworkInterface.html
... you might find some of the "primitive" routing stuff with a few tricks, but not all :
Is it possible to get the default gateway IP and MAC addresses in java?
Java finding network interface for default gateway

How can I pre-authorize authopen?

I'm using authopen inside one of my programs to modify files owned by root. As can be seen in the screenshot below authopen asks for a admin password. What I'd like to achieve is that the dialog shows my app's name and then passes the authorization to authopen.
Code
Launching authopen which returns an authorized file descriptor.
int pipe[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, pipe);
if (fork() == 0) { // child
// close parent's pipe
close(pipe[0]);
dup2(pipe[1], STDOUT_FILENO);
const char *authopenPath = "/usr/libexec/authopen";
execl(authopenPath,
authopenPath,
"-stdoutpipe",
[self.device.devicePath fileSystemRepresentation],
NULL);
NSLog(#"Fatal error, we should never reach %s:%d", __FILE__, __LINE__);
exit(-1);
} else { // parent
close(pipe[1]);
}
// get file descriptor through sockets
I'd really like not to use AuthorizationExecuteWithPrivileges because then I'd have to get more rights than I want to.
Apple has added an option to authopen in OS X 10.9 Mavericks that allows exactly this. Prior this seemed to be impossible.
-extauth
specifies that authopen should read one AuthorizationExternalForm structure from stdin,
convert it to an AuthorizationRef, and attempt to use it to authorize the open(2)
operation.
The authorization should refer to the sys.openfile right corresponding to the requested operation.
The authorization data will be read before any additional data supplied on stdin, and will
not be included in data written with -w.
I have not used this yet, so I do not have any sample code. If someone has, please add it to this answer.
I think if you give your app path in the 1st arg:
execl(authopenPath,
"app path", // <--
"-stdoutpipe",
[self.device.devicePath fileSystemRepresentation],
NULL);
the dialog will show:
"app namerequires that you type your password"
You need to be looking directly at the security framework, introduced in 10.4, I think, and been the main authorization source since 10.5. OSX still works within PAM (like Linux), but /etc/authorization now supersedes this. Apple does have one or two samples of code on how you could pragmatically create a class/entry for someone to authorize themselves against (or preauthorize/be preauthorized like folks who are allowed to print).
This question is old but it seems to be possible, as explained in this technical note :
Technical Note TN2095 : Authorization for Everyone
http://developer.apple.com/library/mac/#technotes/tn2095/_index.html

Resources