Estoy intentando hacer un socket raw para, entre otras cosas, simular un ping (ICMP echo request), entonces intenté escribir un simple código en c (JNI) con ndk porque no tenia idea de cómo hacerlo en java.
Pero el problema es que me tira un error cuando construye el socket porque intenta conectarse al puerto 1024 y necesita permisos. La pregunta sería cómo le doy permisos de root al código que escribí en c. El código en c sería algo como esto:
#define DEFAULT_INIT_PORT 1 /* puerto inicial del escaneo por defecto */
#define DEFAULT_END_PORT 1024 /* puerto final del escaneo por defecto */
#define DEFAULT_ICMP_PORT 8765 /* puerto por defecto para mandar los paquetes ICMP */
extern "C" {
JNIEXPORT jstring JNICALL
Java_com_exadddmple_pingconc_MainActivity_InvokeNativeFunction(JNIEnv * env, jobject obj);
};
JNIEXPORT jstring JNICALL
Java_com_exadddmple_pingconc_MainActivity_InvokeNativeFunction(JNIEnv * env, jobject obj)
{
int sockfd,numbytes,flags,listen;
int init_port, end_port;
int result,fromlen;
struct hostent *he;
struct sockaddr_in their_addr;
static u_char paquete_salida[64];
register struct icmp *cabecera_icmp = (struct icmp *) paquete_salida;
fd_set fd_leer,fd_escribir;
struct timeval tv;
char recv_ICMP[512],shost[100];
struct servent *bar;
int i,val,len=sizeof(val);
init_port= DEFAULT_INIT_PORT;
end_port= DEFAULT_END_PORT;
if (setuid(0))
{
return env->NewStringUTF(" ERROR setuid");
}
if ((sockfd = socket(AF_INET, SOCK_RAW,1)) < 0)
{
return env->NewStringUTF("Error socket");
//exit(1);
}
if ((he= gethostbyname("www.google.com")) == NULL)
{
return env->NewStringUTF("Error gethostbyname");
//exit(1);
}
their_addr.sin_family = AF_INET; // host byte order
their_addr.sin_port = htons(DEFAULT_ICMP_PORT); /* network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr); // dirección IP
bzero(&(their_addr.sin_zero), 8);
sprintf(shost,"%d.%d.%d.%d",(unsigned char)he->h_addr_list[0][0],(unsigned char)he->h_addr_list[0][1],(unsigned char)he->h_addr_list[0][2],\
(unsigned char)he->h_addr_list[0][3]);
/* configuración cabecera mensaje ICMP */
cabecera_icmp->icmp_type = ICMP_ECHO; // Tipo de mensajes ICMP
cabecera_icmp->icmp_code = 0; // Código de mensaje ICMP
cabecera_icmp->icmp_cksum = 0; // Checksum del paquete ICMP
cabecera_icmp->icmp_seq =1; // Numero de secuencia
cabecera_icmp->icmp_id = 0x1111; // ID de paquete
if ((numbytes=sendto(sockfd, &paquete_salida, 64, 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
{
return env->NewStringUTF("Error sendto");
}
do {
FD_ZERO(&fd_leer); // pone a 0 todos los bits de fd_var.
FD_SET(sockfd, &fd_leer); //activa en fd_leer el bit correspondiente al descriptor sockfd
tv.tv_sec=2; // 2 segundos de tiempo de espera para recibir la respuesta al ICMP
tv.tv_usec=0;
result = select(sockfd +1, &fd_leer, NULL, NULL, &tv);
} while (result == -1 && errno == EINTR);
if (result > 0) {
if (FD_ISSET(sockfd, &fd_leer)) {
/* El socket tiene datos para leer */
result = recvfrom(sockfd, recv_ICMP, sizeof recv_ICMP, 0, NULL, &fromlen);
if (result == 0) {
/* Conexión cerrada por el host */
close(sockfd);
return env->NewStringUTF("El host ha cerrado la conexión.");
}
else {
close(sockfd);
return env->NewStringUTF("El host está activo,procederemos a chequear los servicios...");
}
}
}
}