Greetings,
I would like to ask if there's a way to block website(s) from access on a computer(s) dynamically? I mean could this functionality be coded (on java native interface)?
Your response is highly appreciated.
Thanks,
Cyril H.
Yes, you can code a simple HTTP proxy service with Java:
http://www.java2s.com/Code/Java/Network-Protocol/Asimpleproxyserver.htm
Alternatively, there are plenty of existing proxy solutions out there might suit your needs out of the box:
http://www.roseindia.net/opensource/freeproxyservers.php
You would then configure the software/devices that access websites (e.g., your browser) to point to that proxy, so that all HTTP communication passed through it.
Your proxy could then restrict access to whatever URL(s) you wanted to, based on whatever logic you wanted to code up.
If you wanted to get really fancy/secure and require folks to use the proxy (and not to choose to bypass it), you could do that, but that's probably more than you need to, given your question.
You could append entries to your hosts file using the Files class, as shown in this post: How to append text to an existing file in Java?.
This works on all platforms (yes, all of them: including Windows, Mac, Linux, Android, and more), and blocks access for all browsers, without the need for a proxy or special browser extensions (which can be deleted in most cases).
Here is some simple code to start you off. Feel free to edit it to fit your needs:
public void blockSite(String url) {
// Note that this code only works in Java 7+,
// refer to the above link about appending files for more info
// Get OS name
String OS = System.getProperty("os.name").toLowerCase();
// Use OS name to find correct location of hosts file
String hostsFile = "";
if ((OS.indexOf("win") >= 0)) {
// Doesn't work before Windows 2000
hostsFile = "C:\\Windows\\System32\\drivers\\etc\\hosts";
} else if ((OS.indexOf("mac") >= 0)) {
// Doesn't work before OS X 10.2
hostsFile = "etc/hosts";
} else if ((OS.indexOf("nux") >= 0)) {
hostsFile = "/etc/hosts";
} else {
// Handle error when platform is not Windows, Mac, or Linux
System.err.println("Sorry, but your OS doesn't support blocking.");
System.exit(0);
}
// Actually block site
Files.write(Paths.get(hostsFile),
("127.0.0.1 " + url).getBytes(),
StandardOpenOption.APPEND);
}
Imports for above method:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
Sample usage:
blockSite("www.example.com");
Note:
This needs to be run as an administrator (Windows) or using sudo (Mac, Linux).
This might not work for some platforms, as it was only tested on Ubuntu Linux.
P.S. If you're making parental control software, you should also look into blocking programs. Not all things you would want to block are on the Internet. Here is some simple code for that:
/**
Blocks programs.
#param programs - The array of process names.
#param timeout - The time between blocks, in milliseconds.
This parameter should not be set below 100, to avoid slowdown.
#author https://stackoverflow.com/users/5905216/h-a-sanger
*/
public void blockPrograms(int timeout, String...programs) throws IOException {
// Get OS name
String OS = System.getProperty("os.name").toLowerCase();
// Identify correct blocking command for OS
String command = "";
if ((OS.indexOf("win") >= 0)) {
command = "taskkill /f /im ";
} else if ((OS.indexOf("mac") >= 0) || (OS.indexOf("nux") >= 0)) {
command = "killall ";
} else {
// Handle error when platform is not Windows, Mac, or Linux
System.err.println("Sorry, but your OS doesn't support blocking.");
System.exit(0);
}
// Start blocking!
while(true) {
// Cycle through programs list
for(int i = 0; i < programs.length; i++) {
// Block program
Runtime.getRuntime().exec(command + programs[i]);
}
// Timeout
try { Thread.sleep(timeout); } catch(InterruptedException e) {}
}
}
Imports for above code:
import java.io.IOException;
Sample usage:
blockPrograms(100, "chrome", "firefox");
Again, let me note this was only tested on Ubuntu Linux.
Related
I've connected two machines in virtual box. I know that the machines are connected because I was able to detect the os of the target windows machine
Aim: Use one machine to shutdown the target windows machine using a java program which accepts a user input: ip
Problem : When the program executes it skips
runtime.exec("shutdown /m /t0 \\" +ip);
Therefore it does not shutdown the targeted computer.
Question: Why is this happening and how can I solve the issue?
import java.io.IOException;
import java.util.Scanner;
public class RemoteShutdown
{
/*Shutdown user's computer*/
public void shutdown(String ip )
{
Runtime runtime = Runtime.getRuntime();
try
{
runtime.exec("shutdown /s /m \\" +ip);
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception
{
Scanner scanner = new Scanner(System.in);
RemoteShutdown shutDown = new RemoteShutdown();
System.out.print("Enter computer IP: ");
String IP = scanner.next().trim();
shutDown.shutdown(IP);
}
}
relative paths are usually a bad idea in runtime.exec. You have little control of the path; a better option would be to fetch the windows home dir via System.getenv and craft your own route to C:\Windows\System32, or wherever 'shutdown.exe' lives.
Usually this needs admin access, so what you want may be impossible, or may requiring launching java with admin rights.
Generally, don't use exec, but use ProcessBuilder. Trying to navigate how args are split is rather confusing with just the basic exec.
In java, \ in a string is an escape single. "\\" is a string containing only one backslash, but you want to send 2 backslashes to windows here, so, in java, you'd write "\\\\" + ip.
exec returns a Process object, and you tell it to combine output and error, and then you can fetch the output and error streams. This helps a lot: In this case, no doubt shutdown.exe is telling you that the specification of the other computer is erroneous (due to, effectively, a missing backslash), but you never read this data. A web search for 'ProcessBuilder java example read output' will probably get you multiple in-depth posts.
This is a simple Java application which displays the default code page on Windows:
package doscommand;
import java.io.IOException;
import java.io.InputStream;
public class DosCommand {
public static void main(String[] args) throws IOException {
InputStream in = Runtime.getRuntime().exec("chcp.com").getInputStream();
int ch;
StringBuilder chcpResponse = new StringBuilder();
while ((ch = in.read()) != -1) {
chcpResponse.append((char) ch);
}
System.out.println(chcpResponse); // For example: "Active code page: 437"
}
}
On my Windows 10 machine this application always displays "Active code page: 437" because Cp437 is the default, and Runtime.getRuntime().exec() starts a new Process when running chcp.com.
Is it possible to create a Java application which instead displays the currently active code page for the existing Command Prompt window in which the code is running?
I want to be able to do something like this from the Command Prompt:
chcp 1252
java -jar "D:\NB82\DosCommand\dist\DosCommand.jar" REM Shows current code page is "1252".
chcp 850
java -jar "D:\NB82\DosCommand\dist\DosCommand.jar" REM Shows current code page is "850".
How do you specify a Java file.encoding value consistent with the underlying Windows code page? asked a similar question, though in that case the OP was seeking a non-Java solution.
I'd prefer a Java-only solution, but as alternatives:
Can this possibly be done using JNI, by calling some C/C++/C# code with access to the Windows API? The called code need only return a numeric value for the active code page.
I'll accept an answer which persuasively argues that it can't be done.
The solution turned out to be just one line of code. Using JNA, the value returned by the Windows API function GetConsoleCP() gives the console's active code page:
import com.sun.jna.platform.win32.Kernel32;
public class JnaActiveCodePage {
public static void main(String[] args) {
System.out.println("" + JnaActiveCodePage.getActiveInputCodePage());
}
/**
* Calls the Windows function GetConsoleCP() to get the active code page using JNA.
* "jna.jar" and "jna-platform.jar" must be on the classpath.
*
* #return the code page number.
*/
public static int getActiveInputCodePage() {
return Kernel32.INSTANCE.GetConsoleCP();
}
}
How to get the number of open File descriptors under Windows?
On unix there is this:
UnixOperatingSystemMXBean.getOpenFileDescriptorCount()
But there doesn't seem to be an equivalent for windows?
This was going to be a comment but got a little long winded.
Conflicting answers as to why there may be a lack of equivalence here on ServerFault: Windows Server 2008 R2 max open files limit. TLDR: Windows is only limited by available hardware vs Windows is limited by 32 vs 64 bit implementation (MS Technet Blog Post - Pushing the Limits of Windows: Handles). Granted, this is old information.
But! if you note the JavaDocs for the com.sun.management package, you will of course note the conspicuous absence of a Windows version of the the UnixOperatingSystemMXBean that would extend OperatingSystemMXBean to provide the functionality. Even UnixOperatingSystemMXBean only exists to provide getMaxFileDescriptorCount() and getOpenFileDescriptorCount() so it seems unlikely that Windows has the same concept.
Edit:
I did find a nice little program that sort of shows this off, which I tweaked.
Descriptors.java
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
class Descriptors {
public static void main(String [ ] args) {
System.out.println(osMxBean.getClass().getName());
OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean();
try {
Method getMaxFileDescriptorCountField = osMxBean.getClass().getDeclaredMethod("getMaxFileDescriptorCount");
Method getOpenFileDescriptorCountField = osMxBean.getClass().getDeclaredMethod("getOpenFileDescriptorCount");
getMaxFileDescriptorCountField.setAccessible(true);
getOpenFileDescriptorCountField.setAccessible(true);
System.out.println(getOpenFileDescriptorCountField.invoke(osMxBean) + "/" + getMaxFileDescriptorCountField.invoke(osMxBean));
} catch (Exception e) {
e.printStackTrace();
}
}
}
On Linux:
com.sun.management.UnixOperatingSystem
11/2048
On Windows:
sun.management.OperatingSystemImpl
java.lang.NoSuchMethodException:
sun.management.OperatingSystemImpl.getMaxFileDescriptorCount()
at java.lang.Class.getDeclaredMethod(Unknown Source)
at Descriptors.main(Descriptors.java:10)
I am trying to print out all of the capture devices that are supported using the #getDeviceList() method in the CaptureDeviceManager class and the returned Vector has a size of 0.
Why is that? I have a webcam that works - so there should be at least one. I am running Mac OS X Lion - using JMF 2.1.1e.
Thanks!
CaptureDeviceManager.getDeviceList(Format format) does not detect devices. Instead it reads from the JMF registry which is the jmf.properties file. It searches for the jmf.properties file in the classpath.
If your JMF install has succeeded, then the classpath would have been configured to include all the relevant JMF jars and directories. The JMF install comes with a jmf.properties file included in the 'lib' folder under the JMF installation directory. This means the jmf.properties would be located by JMStudio and you would usually see the JMStudio application executing correctly. (If your JMF install is under 'C:\Program Files', then run as administrator to get around UAC)
When you create your own application to detect the devices, the problem you described above might occur. I have seen a few questions related to the same problem. This is because your application's classpath might be different and might not include the environment classpath. Check out your IDE's properties here. The problem is that CaptureDeviceManager cannot find the jmf.properties file because it is not there.
As you have found out correctly, you can copy the jmf.properties file from the JMF installation folder. It would contain the correct device list since JMF detects it during the install (Check it out just to make sure anyway).
If you want do device detection yourself, then create an empty jmf.properties file and put it somewhere in your classpath (it might throw a java.io.EOFException initially during execution but that's properly handled by the JMF classes). Then use the following code for detecting webcams...
import javax.media.*;
import java.util.*;
public static void main(String[] args) {
VFWAuto vfwObj = new VFWAuto();
Vector devices = CaptureDeviceManager.getDeviceList(null);
Enumeration deviceEnum = devices.elements();
System.out.println("Device count : " + devices.size());
while (deviceEnum.hasMoreElements()) {
CaptureDeviceInfo cdi = (CaptureDeviceInfo) deviceEnum.nextElement();
System.out.println("Device : " + cdi.getName());
}
}
The code for the VFWAuto class is given below. This is part of the JMStudio source code. You can get a good idea on how the devices are detected and recorded in the registry. Put both classes in the same package when you test. Disregard the main method in the VFWAuto class.
import com.sun.media.protocol.vfw.VFWCapture;
import java.util.*;
import javax.media.*;
public class VFWAuto {
public VFWAuto() {
Vector devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
Enumeration enum = devices.elements();
while (enum.hasMoreElements()) {
CaptureDeviceInfo cdi = (CaptureDeviceInfo) enum.nextElement();
String name = cdi.getName();
if (name.startsWith("vfw:"))
CaptureDeviceManager.removeDevice(cdi);
}
int nDevices = 0;
for (int i = 0; i < 10; i++) {
String name = VFWCapture.capGetDriverDescriptionName(i);
if (name != null && name.length() > 1) {
System.err.println("Found device " + name);
System.err.println("Querying device. Please wait...");
com.sun.media.protocol.vfw.VFWSourceStream.autoDetect(i);
nDevices++;
}
}
}
public static void main(String [] args) {
VFWAuto a = new VFWAuto();
System.exit(0);
}
}
Assuming you are on a Windows platform and you have a working web-cam, then this code should detect the device and populate the jmf.properties file. On the next run you can also comment out the VFWAuto section and it's object references and you can see that CaptureDeviceManager reads from the jmf.properties file.
The VFWAuto class is part of jmf.jar. You can also see the DirectSoundAuto and JavaSoundAuto classes for detecting audio devices in the JMStudio sample source code. Try it out the same way as you did for VFWAuto.
My configuration was Windows 7 64 bit + JMF 2.1.1e windows performance pack + a web-cam.
I had the same issue and I solved by invoking flush() on my ObjectInputStream object.
According to the API documentation for ObjectInputStream's constructor:
The stream header containing the magic number and version number are read from the stream and verified. This method will block until the corresponding ObjectOutputStream has written and flushed the header.
This is a very important point to be aware of when trying to send objects in both directions over a socket because opening the streams in the wrong order will cause deadlock.
Consider for example what would happen if both client and server tried to construct an ObjectInputStream from a socket's input stream, prior to either constructing the corresponding ObjectOutputStream. The ObjectInputStream constructor on the client would block, waiting for the magic number and version number to arrive over the connection, while at the same time the ObjectInputStream constructor on the server side would also block for the same reason. Hence, deadlock.
Because of this, you should always make it a practice in your code to open the ObjectOutputStream and flush it first, before you open the ObjectInputStream. The ObjectOutputStream constructor will not block, and invoking flush() will force the magic number and version number to travel over the wire. If you follow this practice in both your client and server, you shouldn't have a problem with deadlock.
Credit goes to Tim Rohaly and his explanation here.
Before calling CaptureDeviceManager.getDeviceList(), the available devices must be loaded into the memory first.
You can do it manually by running JMFRegistry after installing JMF.
or do it programmatically with the help of the extension library FMJ (Free Media in Java). Here is the code:
import java.lang.reflect.Field;
import java.util.Vector;
import javax.media.*;
import javax.media.format.RGBFormat;
import net.sf.fmj.media.cdp.GlobalCaptureDevicePlugger;
public class FMJSandbox {
static {
System.setProperty("java.library.path", "D:/fmj-sf/native/win32-x86/");
try {
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
GlobalCaptureDevicePlugger.addCaptureDevices();
Vector deviceInfo = CaptureDeviceManager.getDeviceList(new RGBFormat());
System.out.println(deviceInfo.size());
for (Object obj : deviceInfo ) {
System.out.println(obj);
}
}
}
Here is the output:
USB2.0 Camera : civil:\\?\usb#vid_5986&pid_02d3&mi_00#7&584a19f&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global
RGB, -1-bit, Masks=-1:-1:-1, PixelStride=-1, LineStride=-1
Ok, I know that System.getProperty("os.name") will give me the name of the OS I'm running under, but that's not a lot of help. What I need to know is if the OS I'm running on is a 'Unix-like' OS, I don't care if it's HP-UX, AIX, Mac OS X or whatever.
From the list of possible os.name values it seems like a quick and dirty way of detecting a 'Unix-like' OS is checking if os.name does not contain "Windows". The false positives that will give me are OSes my code is very unlikely to encounter! Still, I'd love to know a better way if there is one.
Use the org.apache.commons.lang.SystemUtils utility class from Commons Lang, it has a nice IS_OS_UNIX constant. From the javadoc:
Is true if this is a POSIX compilant
system, as in any of AIX, HP-UX, Irix,
Linux, MacOSX, Solaris or SUN OS.
The field will return false if OS_NAME
is null.
And the test becomes:
if (SystemUtils.IS_OS_UNIX) {
...
}
Simple, effective, easy to read, no cryptic tricks.
I've used your scheme in production code on Windows XP, Vista, Win7, Mac OS 10.3 - 10.6 and a variety of Linux distros without an issue:
if (System.getProperty("os.name").startsWith("Windows")) {
// includes: Windows 2000, Windows 95, Windows 98, Windows NT, Windows Vista, Windows XP
} else {
// everything else
}
Essentially, detect Unix-like by not detecting Windows.
File.listRoots() will give you an array of the file system root directories.
If you are on a Unix-like system, then the array should contain a single entry "/" and on Windows systems you'll get something like ["C:", "D:", ...]
Edit: #chris_l: I totally forgot about mobile phones. Some digging turns up that Android returns a "/\0\0" - a slash followed by two null bytes (assumed to be a bug). Looks like we avoid false positives for the time being through luck and coincidence. Couldn't find good data on other phones, unfortunately.
It's probably not a good idea to run the same code on desktops and mobile phones regardless, but it is interesting to know. Looks like it comes down to needing to check for specific features instead of simply the system type.
Javadoc says: On UNIX systems the value of this
* field is '/'; on Microsoft Windows systems it is '\'.
System.out.println( File.separatorChar == '/' ? "Unix" : "Windows" );
System.getProperty("os.name"); is about the best you are going to get.
I agree with #Fuzzy in that I think the only way that Java intended you to be able to get that information was through the os.name property.
The only other things I can think of are:
Have a shell script or batch file wrapper to launch your Java app that passes in OS information using the -D argument to the JVM. Though given your description, this doesn't sound doable.
You could try to check for the existence of an OS-specific directory. For instance, you could assume the directory "/" will always exist on a Unix-like system, but not on Windows and do something like this:
if((new File("/")).exists())
{
System.out.println("I'm on a Unix system!");
}
Try to kick off a Unix-specific command line command like ls and check the return code. If it worked, you're on a Unix-like system, if not you're on Windows.
All of those solutions are really just hacks though and frankly I don't really feel all that great about any of them. You're unfortunately probably best off with your original thought. Fun, eh?
Use File.pathSeparator or File.separator. The first will return ";" in Windows and ":" in Unix. The second will return "\" in Windows and "/" in Unix.
You could try to execute the uname command - should be available on all unixoid systems.
package com.appspot.x19290;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class UnixCheck {
public static void main(String[] args) {
UnixCheck s = UnixCheck.S;
String isUnix = s.unix ? "is Unix" : "not Unix";
try {
System.out.println(isUnix + ", devnull: " + s.devnull.getPath());
} catch (NullPointerException e) {
System.out.println(isUnix + ", devnull: unknown");
}
}
public static final UnixCheck S = new UnixCheck();
public static final UnixCheck TEST = new UnixCheck(true);
public final boolean unix;
public final File devnull;
private UnixCheck() {
this(false);
}
private UnixCheck(boolean testing) {
String path;
path = testing ? "/<dev>/<no><such><null><device>" : "/dev/null";
File devnull = devnullOrNone(path);
if (devnull == null) {
this.unix = false;
path = testing ? "<no><such><null><device>" : "nul";
this.devnull = devnullOrNone(path);
} else {
this.unix = true;
this.devnull = devnull;
}
}
private static File devnullOrNone(String name) {
File file = new File(name);
if (file.isFile())
return null;
if (file.isDirectory())
return null;
try {
FileInputStream i = new FileInputStream(file);
try {
i.read();
} finally {
i.close();
}
} catch (IOException e) {
return null;
}
return file;
}
}