How to specify the source port for an http request in iOS - ios

I know that it's an unusual thing to need to do, but I need to specify the SOURCE port to be used in an outgoing http(s) request in iOS. I know that there are many different 'standard' ways to send http(s) requests -- from what I understand the most usual involve NSURLConnection and NSURLSession, but I couldn't see if I can specify the source port. Is it possible to somehow use a socket interface to create the socket and then use this socket with NSURLConnection or NSURLSession?
Or perhaps (as a hack) can one specify the ephemeral port range that my app can use (so I'll restrict it to a range of 5 or 10 ports)?
As a last grasping at straws: is there some ip masquerading or other rules that are available on the iOS device that the app could use to ensure that the source port is correct? (I suppose one could write a process which just does masquerading by hand to the correct fixed port -- essentially write a local http forwarding proxy -- is that my only possibility?)
I don't need any fancy feature or control of these http(s) requests except that they need to come from a certain very narrow range of port numbers.
thanks very much.
If you want to ask why I have such a stupid requirement, please feel free to ask privately -- but don't clutter up this question. THanks!!
I note that just a year ago, iOS: how to get the http connection's source port was asked, but that asked about READING the ephemeral port chosen by the system.
thanks

Related

How can I get the exactly ip address which used to connect in iOS?

I created a request using a domain name, e.g., http://www.google.com. But how could I get the exactly ip address which the framework used to connect to the server?
I knew that the gethostbyname method or the nslookup method could give us the address, but since the ip address is dynamic allocated, maybe the ip address I request that time is different with these methods returned.
So is there a way for me to get the real requested ip address? (I wanted to get the ip programmatically, rather than using tcpdump, etc.)
When you say "which the framework used" here, I assume you mean NSURLSession, NSURLConnection, UIWebView, or WKWebView. Each of those is a slightly different situation, but in all of them, the answer is that it's not possible directly (but see below; it's possible indirectly). You have no access to the underlying sockets that any of them use. All of them use connection pooling, which complicates things slightly even if you could get "the socket." And in the case of UIWebView and WKWebView, a single request to www.google.com may generate several independent connections, each of which could potentially interact with a different IP address.
(I'm a bit fascinated about what you're trying to do. Due to load balancing, a single IP address doesn't mean a single server, so IP addresses are only marginally more identifying than CNAMEs. Mixing in reverse proxies....)
If you need this kind of access, you have to manage the socket yourself. That's generally possible with all of the systems except WKWebView. I'll assume that you know already (or can easily study) how to create a socket and perform HTTP using CFSocket and CFHTTPMessage. This is extensively covered in the CFNetwork Programming Guide. If you've created the socket, you can use CFSocketCopyPeerAddress to check what host you really connected to. That's the piece you wanted.
Given you are able to create this kind of socket and manage it yourself, you can hook that into the major URL loaders (except WKWebView) using an NSURLProtocol. See Drop-in Offline Caching for UIWebView (and NSURLProtocol) for a quick introduction and some sample code. You just need to take the request and make it yourself with CFSocket, giving you the chance to see the exact port you're connected to.
Your browser or whatever other tool you use to make a HTTP request will look up the address at the time of doing the request. On any reasonable system, they will use the same method for looking up the address as gethostbyname does, except that there might be local caching in the browser (which you can usually turn off or clear).
The request might get a redirection response to make the same request to a different location. These are often used for load balancing, etc. The only straightforward way I can see that you would be able to find out the 'ultimate destination' behind these, would be to make the request programmatically and record the details of any redirections, Of course, it is the nature of load balancing that you might redirected to a slightly different server each time.
This has nothing to do with 'dynamic allocation of IP addresses' by the way. If the IP address of www.google.com changes, it is likely to be not because the same server has been allocated a different IP address, but because requests are being directed to a different machine.
In case you are using NSURLSession to obtain a URLSessionStreamTask, you can capture the underlying streams using -captureStreams. This will invoke the -URLSession:streamTask:didBecomeInputStream:outputStream: delegate method, giving you a NSInputStream and a NSOutputStream. NSInputStream is toll-free bridged to CFReadStreamRef and using CFReadStreamCopyProperty() and the constant kCFStreamPropertySocketNativeHandle provides you with the native socket handle, which you can pass into getpeername(). For Upload-, Download- and DataTasks, no such possibility seems to exist.

How can I check that a computer can access a certain URL and send and receive e-mail?

With Delphi XE2, what is the most reliable method to detect if the computer is able to do the following things?
reach a specific website with HTTP which does not have a fixed IP address
send and receive e-mail with any local or remote e-mail client
There are too many factors involved (type of Internet connection, firewall/router rules, proxies, etc). The most reliable approach is to simply not try to determine the current state and just attempt the desired operation (perform the actual HTTP request, or the SMTP/POP3/IMAP operation, etc), and just be prepared to react to any errors. You can detect connection-related errors and prompt the user to check their Internet connection before retrying.
Use TIdHTTP.Get and try to download http://google.com.
Of course it depends on the definition of being connected to the internet. Sometimes web traffic (port 80) is blocked while other ports are open. Fortunately, nowadays most people are actually allowed to browse the web, since it also provides help with their daily activities. Google is probably one of the least firewalled websites with one of the highest uptimes.
But still, it's a lucky guess. Depending on what you need it for, you might as well just try your thing and see if it works. If not, apparently the computer was not properly connected, even if it could reach Google. :)
[edit]
Because of the discussion. InternetCheckConnection is a good alternative too, but it also checks the connection by pinging an actual server.
MSDN says
Use the InternetCheckConnection function to check the connection to
the Internet. It attempts to ping the server designated by the URL
that is passed to the function. If the FLAG_ICC_FORCE_CONNECTION flag
is set and the URL is NULL, the function checks to see if there is an
entry in the server database for the nearest server. If one exists,
the function pings that server
But since this function uses ping, it may be a bit faster than actually retrieving content. On the other hand, many firewalls actively refuse pings.

Programmatic Method For Opening Ports

I've searched this subject in stackoverflow and found out that a telnet library would help, and I found a telnet lib here: C# Telnet Library
but I don't know how I can use a telnet library to open a port in my router. I'm using an AT&T 2wire router. Any hints on how I can do this?
You can't. The 2wire router is an island unto itself, if it decides to block a port nothing external can (or should) be able to change that. You are on the wrong track, and would need to restate your goals in order to get a useful answer.
UPnP and other "Hole Punching" techniques do exist: but you'll be in a world of hurt if you try to reply on them for any widespread deployment.
Perhaps you meant to open a connection to a remote server and then establish two way communication. That is easy... and how other games and tools get the job done.
Technically speaking you should not be able to. You shouldn't have outside programatic access to a router to open a port if it's blocked.
If what you mean is opening a port for communication (that is not blocked) then you can simply create Sockets with the address and port (ex. localhost 7777) to establish inter process communication or simply communication with another server.
As I mentioned in a comment below there are ports that are available for use (in C# this can be easily tested, a quick google search will find you many snippets of code for testing if a port is open). A simple approach is to simply start at port 1024 (I believe this is the correct lower bound for ports that should be used by applications, someone correct me if I'm wrong) and just start counting up until you find a port that is available, if you find you've reached some upper limit you can simply report that a connection cannot be made. I hope this clears up a little more and if I have time I will try to find some code I have for this and edit it in but honestly a quick search can net you similar code for checking ports in C#.

How to look for any and all computers on a network which are using my service?

I have a custom pair of client/server sockets (TJDServerSocket and TJDClientSocket) which wrap the TServerSocket and TClientSocket in the ScktComp unit. I don't have any issues to fix, but would like to know something. I'd like to add a feature to the client side to automatically search the network for any instances of a server socket (specifically my server component).
I'm open to any suggestions, but has to be specific to the use of the ScktComp unit in Delphi 7.
Here's a link to the components of mine.
Never used the TServerSocket and TClientSocket myself, and I don't have the help files within reach, so I can't immediately see if this would work with those components.
For a project I did I needed something like that too. I ended up with using UDP to broadcast a discovery request (within the same subnet of course). The server, listening on a particular port for such a request, would reply its data back. When multiple servers would exist (a situation that though rare could occur) the client just picked the server with the required service(s) and the least load. That load was part of the data the server send back.
It worked out nice, wasn't all that difficult to write, and turned out reasonably efficient too.
The request protocol is completely up to you. The one I devised allowed clients to send a request detailing the services they need, and servers replying listing their services and the load (= connected clients in active use).
After selecting the server to talk to, a client would register itself for the services it needed, and could use them after that.
Hope this helps.
There are some standard protocols for service discovery. See for example: http://en.wikipedia.org/wiki/Zero_configuration_networking
Mailslots is a nice option here. It'll broadcast to every PC on your subnet. See Jeroen's answer to this question:
Suggestions on writing a TCP IP messaging system (Client/Server) using Delphi 2010
Searching is as easy as port scanning.
If you don't like the brute force approach, the server can register itself to a well known service application (could be a web server), and the client can connect to the service application to ask. It's quieter than broadcasting.
With more information, such as details about the network (who's it for?), I can suggest a more precise answer.

How can I transload data between two delphi applications over internet?

Hi
let me make my question clear. Two people using my app are connected to the internet. Both have each other's IP and they want to chat (like Y!messanger) with each other.
I think I need to use Indy components; right? Which component should I use?
Thanks in advance
Have you looked at any of the demos on Indy's website yet?
In general, you are looking to create a "Client/Server" type application. A quick Google search for "indy client server example" pulls up lots of results, including this one: http://www.devarticles.com/c/a/Delphi-Kylix/A-Real-World-Client-Server-Application-in-Delphi/
In reality, this gets a lot more complicated when you have firewalls and NATs with private IP addresses. You will have to consider how your application will either get around or through these types of technologies.
Similar to what Scott said, I think that your biggest problem is getting them talking to each other. My computers at home go through a router, which blocks all incoming connection requests (i.e. requests to start a conversation between two computers) from the Internet. My computers can send connection requests OUT, and start a conversation that way, but unless you modify the router (port forwarding) my computers can not receive connection requests.
You need a server somewhere to which both people will connect, that can then relay messages back and forth. To get really tricky, once the connection is made to the server the two computers can then be put into direct contact, but that involves UDP packets and some clever magic.
You don't have to use Indy components, you just need anything that will handle communications over the network. Any HTTP or sockets network stack will do. Indy is the defacto standard for Delphi Win32.
To do network communications, you will need to create a listener object or service on machine A and a sender object on machine B to send a network message from A to B. To send a message from B to A, you will need a reverse path as well - 4 objects total to perform bidirectional comms. Some object wrappers hide this detail internally. I don't recall offhand whether Indy hides this or not.
It would probably be easiest if you use a common TCP/IP protocol for your machine to machine communications, such as HTTP. This will make it easier to get your connections through firewalls and proxies that frequently exist between arbitrary users. To avoid conflicting with any HTTP web services that might be running on either machine, you should use a custom port number with the IP address: 192.168.1.10:12345, not the standard HTTP web server port 80. This is what most of the IM clients do.

Resources