4

I have a server application that runs in a hosted environment but creates print jobs in the client's local network (behind NAT; the mechanics of this is not relevant).

In order to send the print job to the printer that is attached to the workstation, I need to identify the workstation. The users move around between workstations, so I can't permanently associate a user with a workstation/printer. The trivial solution is to require the user to identify the machine he is logging in from, for instance by selecting from a list, but that's an inconvenience and subject to user error.

Options I have eliminated:

  • Host header variables (nothing identifiable is sent)
  • Cookies, in support of a user selection. This somewhat addresses the potential for user error, but not really.
  • HTML5 DOM Storage - is not supported by the client's browser

Any other ideas?

Edit: I do have the option of puttnig this particular function (create a print job) into a thick client app. The app can then of course be configured and the problem goes away. But the user experience will suffer from having to switch between the browser and a Windows app.

cdonner
  • 37,019
  • 22
  • 105
  • 153
  • And you cant just set a response type and Response.Write() the bits to the client so they can print to whatever printer they want? Its kind of how every other web application (sans dedicated print server) does it. – StingyJack Jan 05 '11 at 21:22
  • There are some methods published for creating a "fingerprint" of a client machine. There was some heavy discussion on the net about Canvas Fingerprinting for example - search for "Client Fingerprinting" and "Canvas Fingerprinting" etc. – George Birbilis Feb 18 '15 at 16:47

3 Answers3

9

I won't discuss your strange scenario, just answer your question: how to identify a machine?

Well, there is no close-form solution at current time with HTTP protocol. All machines share the same IP since they are behind NAT. You can't get MAC address. You can't get hardware identifiers. You can't be sure that all machine will send different headers to the server (ie. all different browsers/version).

You may rely on cookies. Try to create some form of machine authentication, or better, machine identification page, browse it once from each machine telling the server which is the printer to use on that machine, and then set a permanent cookie on that machine.

As soon as cookies won't be deleted (maybe you can always renew the cookie, you never know...) you have a simple mechanism.

It's the best I can suggest :(

usr-local-ΕΨΗΕΛΩΝ
  • 26,101
  • 30
  • 154
  • 305
  • This is the best solution I came up with myself and it's good to hear that I did not miss anything else. Because the machine operators do have individual AD accounts, I will have to visit the "Set Cookie" page once per user, which makes this a little less attractive. – cdonner Jan 05 '11 at 21:38
  • Not once per user: once per machine. The cookie is bound to the browser, not to the user or his session. Just make sure no one clears cookie – usr-local-ΕΨΗΕΛΩΝ Jan 05 '11 at 21:43
  • 1
    Because machine operators log in to the workstation with individual network accounts, they do not share cookies, unfortunately. – cdonner Jan 05 '11 at 21:55
  • 1
    I'm doing this same thing for a website that runs on multiple kiosks. The first time the user goes to the website they have to pick their location, then it sets a permanent cookie. – David Jan 05 '11 at 21:57
  • @cdonner: **that** is a real problem. Another solution could be a browser extension that adds a special header basing on internal IP. You can develop it with .NET and make sure about permissions... No better idea yet – usr-local-ΕΨΗΕΛΩΝ Jan 05 '11 at 21:59
  • @dj: Browser extension may be the answer. I have seen suggestions for using ActiveX controls to solve this issue. I will keep that in mind. – cdonner Jan 05 '11 at 22:08
  • Remember that ActiveX are native-code components, and .NET browser components act exactly like ActiveX (ie. object tag) but are managed code and easier to develop as windows forms – usr-local-ΕΨΗΕΛΩΝ Jan 05 '11 at 22:14
0

If you look up the servervariables when they make a request you will have Request.ServerVariables["REMOTE_ADDR"]; which would probably be the internal IP if the app is internal/intranet. There is also REMOTE_HOST. Sometimes these are filtered off by proxies/firewalls/nat but hopefully not in your situation.

You can also call these on the HTTPRequest object like Request.UserHostAddress. You might need to get it by the current context HTTPContext.Current.Request.UserHostAddress.

If you can't get that then just return the document, data, file to the Request to have them print and choose their printer via Response.BinaryWrite() setting the content type of the file they are accessing.

All servervariables are listed here for IIS since you are using ASP.NET: http://msdn.microsoft.com/en-us/library/ms524602(v=vs.90).aspx

Another possibility is to email it to the user if it is a long running report or allow them to access the document with a log-in to print themselves.

Ryan Christensen
  • 7,843
  • 1
  • 27
  • 25
  • Hmmm... The question makes me think the server is **outside** the NAT, as he didn't want to mention the (possibly complex) mechanics of NAT-traversal printing (port forwarding? UPNP? I don't care) – usr-local-ΕΨΗΕΛΩΝ Jan 05 '11 at 21:29
  • Yeh the problem becomes when you want to push instead of have the client pull. NAT can be bad. UPnP, udp nat punching, forwarding, all sort of stuff comes into play. – Ryan Christensen Jan 05 '11 at 21:32
  • REMOTE_ADDR is the external IP and REMOTE_USER is empty. I mentioned that I already eliminated host header variables as a solution. – cdonner Jan 05 '11 at 21:35
  • If you want to push anything to them or figure out where they are at, you will need to be able to get their internal IP. I would recommend scrapping push and find pull methods to go with. i.e. response it to the browser, email them, make them login and print themselves where the PC will know the printer. All I can think of currently. – Ryan Christensen Jan 05 '11 at 21:38
0

If REMOTE_ADDR is actually working as advertised, have you tried it's brother, REMOTE_HOST? If HOST doesn’t work, but ADDR does, then

RemoteHostOughta = GetHostEntry(Request.ServerVariables("REMOTE_ADDR")).HostName

Unfortunately, there is some setting I don’t know about such that my IIS is getting the server IP (not a router!) instead of the remote when I read REMOTE_ADDR

WGroleau
  • 448
  • 1
  • 9
  • 26