how to get PRINTER's IP using windows API in c++? [duplicate] - windows

How can I get the IP address of a network printer given the port name,
using win32 API?
I tried looking into the PRINTER_INFO_* structs, but it seems it is not present there.

you can get the port name by PRINTER_INFO_2,and the get the ip from the registry,the path is:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Standard TCP/IP Port\Ports
the ip store in "HostName"

I don't think there's a standard way to get the IP address. There are probably different incompatible implementations of network port monitors. For my network printer, the IP address is part of the port name (e.g., IP_192_168.1.104). If it's of that form, then you might be able to parse it out, but I don't think this is universal.
Using EnumPorts you can determine if it's a network printer, but I still don't see a way to get the IP address.

Like any other IP network device, the printer will have an IP address (denoting it's ethernet card), and will run a service on a certain port (identifying the program responding to printer messages). This is merely networking stuff and has nothing yet to do with printer specific stuff.
So given it's port only, there's no way to find it's IP address. Probably the services on all the other printers listen to the same port.
Assuming you mean you have the printer's name, you need to query the name service for your domain. This service maps network addresses to 'symbolic' names.
Using the winsock2 api, I believe it's gethostbyname you need. This will retrieve the host info of your printer by it's name.

I came looking for an answer but didn't really accept there was no way and found that there actually is. This answer is in Delphi, but it's pretty straightforward:
function PortIPAddress(Port: string): string;
var
buf: PWideChar;
pd: PRINTER_DEFAULTS;
c,
d,
bs,
hXcv: cardinal;
begin
Result := 'unknown';
ZeroMemory(#pd, SizeOf(PRINTER_DEFAULTS));
pd.DesiredAccess := SERVER_ACCESS_ADMINISTER;
if OpenPrinter(PAnsiChar(Format(',XcvPort %s', [Port])), hXcv, #pd) then
begin
XcvData(hXcv, 'IPAddress', nil, 0, nil, 0, #bs, #c);
GetMem(buf, bs);
try
if XcvData(hXcv, 'IPAddress', nil, 0, buf, bs, #d, #c) then
Result := buf;
finally
FreeMem(buf, bs);
end;
end;
ClosePrinter(hXcv);
end;

Simply Use Advanced Printer apis, dynamic call

Related

getaddrinfo with flag AI_NUMERICHOST

Please tell me something I can't understand. There is a function getaddrinfo() and there is a flag AI_NUMERICHOST. MSDN says that in getaddrinfo() with this flag, you need to send the numeric value of the IP address, and not the domain name. But why?
I already have an IP address, why should I ask DNS for an IP address?
getaddrinfo() outputs sockaddr_... structs (sockaddr_in or sockaddr_in6) for the requested host/service. It is not just about IP addresses, it is also about other things, like socket types, service ports, etc, depending on your input and hint values.
So, if you already have an IP address in a string format, you can have getaddrinfo() parse that string for you (specifying AI_NUMERICHOST to avoid DNS) into a binary format in the output sockaddr_..., as well as fill in other sockaddr_... fields at the same time.

Golang: net.ParseIP()

some perfectly valid IPv6 addresses are considered IPv4 by net.ParseIP(), e.g. 0000:0000:0000:0000:0000:ffff:0100:0000 / ::ffff:0100:0. (please see https://play.golang.org/p/57jAJVSIrHF for a simple example)
What would be the most idiomatic way to deal with this situation? The net package does not export most of the functionality, so rewriting net.Parse would result in a lot of code duplication.
Thank you in advance for your help!
best regards,
Stefan
What you consider perfectly valid IPv6 addresses like ::ffff:0100:0000 are in fact IPv4 addresses mapped into the IPv6 space, commonly written as ::ffff:1.0.0.0. Thus essentially it is an IPv4 address. See section about IPv4-mapped IPv6 addresses in Wikipedia:IPv6 for more information.
The IPAddress Go library provides more fine-grained control over IPv4-mapped addresses (and other schemes for mapping IPv4 to IPv6). Disclaimer: I am the project manager.
addrStr := ipaddr.NewIPAddressString("::ffff:0100:0")
addr := addrStr.GetAddress()
converter := ipaddr.DefaultAddressConverter{}
var ipv4Addr *ipaddr.IPv4Address
if converter.IsIPv4Convertible(addr) {
ipv4Addr = converter.ToIPv4(addr)
}
fmt.Printf("original IPv4-mapped IPv6 address is %v, IPv4 address is %v",
addr, ipv4Addr)
Output:
original IPv4-mapped IPv6 address is ::ffff:100:0, IPv4 address is 1.0.0.0

How to get local port and IP in Network Kernel Extension(Socket filter) in kernel context of MacOS

I am looking to collect Port and IP of the connecting socket to the socket filter in Network Kernel Extention (NKE).
I have tried to collect it in sf_bind, sf_connect_in, sf_connect_out call back functions of struct sflt_filter.
In sf_bind(void *cookie,socket_t so,const struct sockaddr *to) callback. it specified for to param "The local address of the socket will be bound to" So I have used code:
printf("Local port:<%u> and IP<%04X>",
ntohs(((struct sockaddr_in *)to)->sin_port),
ntohs(((struct sockaddr_in*)to)->sin_addr.s_addr));
Sometimes both IP and Port is empty and sometimes one of the both is appearing.
And in same and other callbacks I have tried with code:
unsigned char szAddrStr[256];
struct sockaddr_in addrLcl;
sock_getsockname(so, (struct sockaddr *)&addrLcl, sizeof(addrLcl));
inet_ntop(AF_INET, &addrLcl.sin_addr, (char *)szAddrStr, sizeof(szAddrStr));
printf("IP String <%s> Port Hex:<%X>", szAddrStr, ntohs(addrLcl.sin_port));
But this code always gives IP and Port empty.
Has anyone had any idea? or another way to get it? Thanks in advance.
About your first code fragment: It's hard to say what is exactly wrong without full callback code sample, but you definetely should check sa_family field of "to" before trying to print sin_port and sin_addr as port and ip.
I think the values you are looking for are AF_INET and AF_INET6.
About your second code fragment: you should again check sa_family;
Also, calling sock_getsockname on "so" in bind callback could be wrong, because that "callbacks" are called before relevant operations and you will not have filled sockaddr for "so".
There is tcplognke sample (it was once on apple developers resources, but they are not good at care about them), you should check it out for examples.
And there is an information about Apple plans to make NKE technology deprecated soon, so be careful using it :)

Windows limitation on number of simultaneously opened sockets/connections per machine

Let's say I have Windows 7 with one real network interface and few loopback interfaces.
I have IOCP enabled server that accepts connections from clients.
I'm trying to simulate as much as possible real client connections to the server.
My client code simply establishes X amount of socket connections
(note that client binds to a given interface):
const Int32 remotePort = 12345;
const Int32 MaxSockets = 60000;
Socket[] s = new Socket[MaxSockets];
IPEndPoint bindEndpoint = new IPEndPoint(IPAddress.Parse(args[0]), 0);
for (Int32 i = 0; i < MaxSockets; i++)
{
s[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s[i].SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
s[i].Bind(bindEndpoint);
s[i].Connect(args[1], remotePort);
IPEndPoint socketInfo = (IPEndPoint)s[i].LocalEndPoint;
Console.WriteLine(String.Format("Connected socket {0} {1} : {2}", i, socketInfo.Address, socketInfo.Port));
}
On a loopback interface I have several IPs that I use for binding.
In addition, I also use real interface to bind on.
I ran into a problem when amount of opened sockets is around 64K per machine:
Unhandled Exception: System.Net.Sockets.SocketException: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full
I've tried several helpless things like:
- setting MaxUserPort to max value and some other recommended TCPIP settings in the registry.
- trying to run two servers on different interfaces (real interfaces and loopback) and using several clients.
Is it a known limitation in Windows or its possible to overcome it somehow?
Thanks for the help!
I have found on some Microsoft page that:
... HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\MaxUserPort
registry subkey is defined as the maximum port up to which ports may be allocated for wildcard binds. The value of the MaxUserPort registry entry defines the dynamic port range...
So, if I force the endpoint to use a certain port, e.g.
IPEndPoint bindEndpoint = new IPEndPoint(IPAddress.Parse(args[0]), 54321);
Then I can open more than 64K simultaneous sockets in the system.
In your code example, you are calling Bind(bindEndpoint), but you do not show how bindEndpoint is defined. Check that :
Your system actually has multiple IP addresses (loopback does not count)
You are actually setting the IP Address of the endpoint to an IP address (not loopback)
The binds are being spread across multiple IP addresses
The loopback address does not count because many systems treat it specially for routing and binding purposes. So binding to ports in loopback may be sucking up the ports across all addresses the same as if you were binding to INADDR_ANY (0.0.0.0).
Both TCP and UDP use an unsigned 16-bit integer to designate port number. I don't imagine any implementation in any operating system is going to be able to open more than 65535 sockets per bound address at best. Additionally, I wouldn't be surprised if Windows doesn't implement fully isolated state tables for each adapter or each bound address but instead relies on a global state table. If that is the case, it would be a Windows network architecture limit instead of a soft, configurable limit.
I've developed a load testing tool.
Running on Windows 10/16G RAM, it could created 60,000 connections with server successfully.
But when try to create more connections, the tool will report "socket WinError 10055 No Buffer Space Available" soon.
Accord to this article, I think the limitation is the overall socket buffer size of whole OS, not the number of opened file.

Find internal IP address with BASH

I am already aware of many ways of getting your internal IP (ifconfig, ip addr, /etc/hosts, etc), but I am trying to write a bash script that will always return the internal IP. The problem is, many one-liners (/sbin/ifconfig|grep inet|head -1|sed 's/\:/ /'|awk '{print $3}') can return multiple IPs, and I need to distinguish the internal one manually.
I suspect that to the computer, there is no difference between and an external IP and an internal IP, and thus no 100%, guaranteed way to get the right IP.
The end result is that this script will return the internal IP, no matter if its a 192 address or a 204 address, etc.
Thanks in advance.
"hostname -i" should hopefully give you the same result
As others have mentioned, a machine is not really guaranteed, or even likely, to have a single IP address. I'm not sure exactly what you mean by "internal IP"; sometimes this can mean "IP address on the local network", i.e. the interface which connects to a NAT-enabled firewall.
I'm thinking that the best way to do this is to connect to a host on the network you want and use the address from which that connection originates. This will be the interface which the machine normally uses to connect to that network. The user Unkwntech had the same idea on this thread. The code below is just taken from that answer.
I don't know if this really qualifies as a "bash" solution, since it's just an inline Python script, but anyway this will get you the local ip address used to reach google.com. So this will give you the IP address of whichever interface the machine uses to reach Internet hosts.
$ python -c 'import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("google.com", 80))
print s.getsockname()[0]'
A more bash-y solution might use tracepath or some similar utility.
Systems can have multiple private IPs too though. You would have to limit your searching on IPs to private IPs. 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16.
Within the RFC 1918 private address spaces, a machine could conceivably have every address in the 10/8 range, the 172.16/12 range, and the 192.168/16 range, for a total of 17891328 IP addresses, and all of them would be legal "internal" IPs.
Oh yes, don't forget IPv6 :) 2^64 possible addresses per network for a single machine, which might participate in multiple networks.
This isn't exactly academic, either: it is quite common for VMWare, VirtualBox, QEMU, etc. host systems to have multiple RFC 1918 addresses assigned; one for the 'usual use', and one that is used specifically to communicate with guest operating systems. Or routers / firewalls, they might have a dozen internal IPs specifically to subnet a network for access control reasons.

Resources